mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
[ACS-5857] migrated adfMomentDate Pipe to date-fns equivalent
This commit is contained in:
@@ -21,6 +21,7 @@ import moment from 'moment';
|
|||||||
import { FormFieldTypes } from './form-field-types';
|
import { FormFieldTypes } from './form-field-types';
|
||||||
import { isNumberValue } from './form-field-utils';
|
import { isNumberValue } from './form-field-utils';
|
||||||
import { FormFieldModel } from './form-field.model';
|
import { FormFieldModel } from './form-field.model';
|
||||||
|
import { format, isAfter, isBefore, isValid, parse } from 'date-fns';
|
||||||
|
|
||||||
export interface FormFieldValidator {
|
export interface FormFieldValidator {
|
||||||
|
|
||||||
@@ -145,10 +146,10 @@ export class DateFieldValidator implements FormFieldValidator {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Validates that the input string is a valid date formatted as <dateFormat> (default D-M-YYYY)
|
// Validates that the input string is a valid date formatted as <dateFormat> (default D-M-YYYY)
|
||||||
static isValidDate(inputDate: string, dateFormat: string = 'D-M-YYYY'): boolean {
|
static isValidDate(inputDate: string, dateFormat: string = 'd-M-yyyy'): boolean {
|
||||||
if (inputDate) {
|
if (inputDate) {
|
||||||
const d = moment(inputDate, dateFormat, true);
|
const d = parseUpdate(inputDate, dateFormat);
|
||||||
return d.isValid();
|
return isValid(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -204,26 +205,26 @@ export class DateTimeFieldValidator implements FormFieldValidator {
|
|||||||
|
|
||||||
export abstract class BoundaryDateFieldValidator implements FormFieldValidator {
|
export abstract class BoundaryDateFieldValidator implements FormFieldValidator {
|
||||||
|
|
||||||
DATE_FORMAT_CLOUD = 'YYYY-MM-DD';
|
DATE_FORMAT_CLOUD = 'yyyy-MM-dd';
|
||||||
DATE_FORMAT = 'DD-MM-YYYY';
|
DATE_FORMAT = 'dd-MM-yyyy';
|
||||||
|
|
||||||
supportedTypes = [
|
supportedTypes = [
|
||||||
FormFieldTypes.DATE
|
FormFieldTypes.DATE
|
||||||
];
|
];
|
||||||
|
|
||||||
validate(field: FormFieldModel): boolean {
|
validate(field: FormFieldModel): boolean {
|
||||||
let isValid = true;
|
let isFieldValid = true;
|
||||||
if (this.isSupported(field) && field.value && field.isVisible) {
|
if (this.isSupported(field) && field.value && field.isVisible) {
|
||||||
const dateFormat = field.dateDisplayFormat;
|
const dateFormat = field.dateDisplayFormat;
|
||||||
|
|
||||||
if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
|
if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
|
||||||
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
|
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
|
||||||
isValid = false;
|
isFieldValid = false;
|
||||||
} else {
|
} else {
|
||||||
isValid = this.checkDate(field, dateFormat);
|
isFieldValid = this.checkDate(field, dateFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isValid;
|
return isFieldValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
extractDateFormat(date: string): string {
|
extractDateFormat(date: string): string {
|
||||||
@@ -240,24 +241,24 @@ export class MinDateFieldValidator extends BoundaryDateFieldValidator {
|
|||||||
|
|
||||||
checkDate(field: FormFieldModel, dateFormat: string): boolean {
|
checkDate(field: FormFieldModel, dateFormat: string): boolean {
|
||||||
|
|
||||||
let isValid = true;
|
let isFieldValid = true;
|
||||||
// remove time and timezone info
|
// remove time and timezone info
|
||||||
let fieldValueData;
|
let fieldValueData;
|
||||||
if (typeof field.value === 'string') {
|
if (typeof field.value === 'string') {
|
||||||
fieldValueData = moment(field.value.split('T')[0], dateFormat);
|
fieldValueData = parseUpdate(field.value.split('T')[0], dateFormat);
|
||||||
} else {
|
} else {
|
||||||
fieldValueData = field.value;
|
fieldValueData = field.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const minValueDateFormat = this.extractDateFormat(field.minValue);
|
const minValueDateFormat = this.extractDateFormat(field.minValue);
|
||||||
const min = moment(field.minValue, minValueDateFormat);
|
const min = parseUpdate(field.minValue, minValueDateFormat);
|
||||||
|
|
||||||
if (fieldValueData.isBefore(min)) {
|
if (isBefore(fieldValueData, min)) {
|
||||||
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`;
|
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`;
|
||||||
field.validationSummary.attributes.set('minValue', min.format(field.dateDisplayFormat).toLocaleUpperCase());
|
field.validationSummary.attributes.set('minValue', formatUpdate(min, field.dateDisplayFormat).toLocaleUpperCase());
|
||||||
isValid = false;
|
isFieldValid = false;
|
||||||
}
|
}
|
||||||
return isValid;
|
return isFieldValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
isSupported(field: FormFieldModel): boolean {
|
isSupported(field: FormFieldModel): boolean {
|
||||||
@@ -270,24 +271,24 @@ export class MaxDateFieldValidator extends BoundaryDateFieldValidator {
|
|||||||
|
|
||||||
checkDate(field: FormFieldModel, dateFormat: string): boolean {
|
checkDate(field: FormFieldModel, dateFormat: string): boolean {
|
||||||
|
|
||||||
let isValid = true;
|
let isFieldValid = true;
|
||||||
// remove time and timezone info
|
// remove time and timezone info
|
||||||
let fieldValueData;
|
let fieldValueData;
|
||||||
if (typeof field.value === 'string') {
|
if (typeof field.value === 'string') {
|
||||||
fieldValueData = moment(field.value.split('T')[0], dateFormat);
|
fieldValueData = parseUpdate(field.value.split('T')[0], dateFormat);
|
||||||
} else {
|
} else {
|
||||||
fieldValueData = field.value;
|
fieldValueData = field.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxValueDateFormat = this.extractDateFormat(field.maxValue);
|
const maxValueDateFormat = this.extractDateFormat(field.maxValue);
|
||||||
const max = moment(field.maxValue, maxValueDateFormat);
|
const max = parseUpdate(field.maxValue, maxValueDateFormat);
|
||||||
|
|
||||||
if (fieldValueData.isAfter(max)) {
|
if (isAfter(fieldValueData, max)) {
|
||||||
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`;
|
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`;
|
||||||
field.validationSummary.attributes.set('maxValue', max.format(field.dateDisplayFormat).toLocaleUpperCase());
|
field.validationSummary.attributes.set('maxValue', formatUpdate(max, field.dateDisplayFormat).toLocaleUpperCase());
|
||||||
isValid = false;
|
isFieldValid = false;
|
||||||
}
|
}
|
||||||
return isValid;
|
return isFieldValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
isSupported(field: FormFieldModel): boolean {
|
isSupported(field: FormFieldModel): boolean {
|
||||||
@@ -309,22 +310,22 @@ export class MinDateTimeFieldValidator implements FormFieldValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate(field: FormFieldModel): boolean {
|
validate(field: FormFieldModel): boolean {
|
||||||
let isValid = true;
|
let isFieldValid = true;
|
||||||
if (this.isSupported(field) && field.value && field.isVisible) {
|
if (this.isSupported(field) && field.value && field.isVisible) {
|
||||||
const dateFormat = field.dateDisplayFormat;
|
const dateFormat = field.dateDisplayFormat;
|
||||||
|
|
||||||
if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
|
if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
|
||||||
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
|
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
|
||||||
isValid = false;
|
isFieldValid = false;
|
||||||
} else {
|
} else {
|
||||||
isValid = this.checkDateTime(field, dateFormat);
|
isFieldValid = this.checkDateTime(field, dateFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isValid;
|
return isFieldValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkDateTime(field: FormFieldModel, dateFormat: string): boolean {
|
private checkDateTime(field: FormFieldModel, dateFormat: string): boolean {
|
||||||
let isValid = true;
|
let isFieldValid = true;
|
||||||
let fieldValueDate;
|
let fieldValueDate;
|
||||||
if (typeof field.value === 'string') {
|
if (typeof field.value === 'string') {
|
||||||
fieldValueDate = moment(field.value, dateFormat);
|
fieldValueDate = moment(field.value, dateFormat);
|
||||||
@@ -336,9 +337,9 @@ export class MinDateTimeFieldValidator implements FormFieldValidator {
|
|||||||
if (fieldValueDate.isBefore(min)) {
|
if (fieldValueDate.isBefore(min)) {
|
||||||
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`;
|
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`;
|
||||||
field.validationSummary.attributes.set('minValue', min.format(field.dateDisplayFormat).replace(':', '-'));
|
field.validationSummary.attributes.set('minValue', min.format(field.dateDisplayFormat).replace(':', '-'));
|
||||||
isValid = false;
|
isFieldValid = false;
|
||||||
}
|
}
|
||||||
return isValid;
|
return isFieldValid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,22 +356,22 @@ export class MaxDateTimeFieldValidator implements FormFieldValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate(field: FormFieldModel): boolean {
|
validate(field: FormFieldModel): boolean {
|
||||||
let isValid = true;
|
let isFieldValid = true;
|
||||||
if (this.isSupported(field) && field.value && field.isVisible) {
|
if (this.isSupported(field) && field.value && field.isVisible) {
|
||||||
const dateFormat = field.dateDisplayFormat;
|
const dateFormat = field.dateDisplayFormat;
|
||||||
|
|
||||||
if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
|
if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
|
||||||
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
|
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
|
||||||
isValid = false;
|
isFieldValid = false;
|
||||||
} else {
|
} else {
|
||||||
isValid = this.checkDateTime(field, dateFormat);
|
isFieldValid = this.checkDateTime(field, dateFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isValid;
|
return isFieldValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkDateTime(field: FormFieldModel, dateFormat: string): boolean {
|
private checkDateTime(field: FormFieldModel, dateFormat: string): boolean {
|
||||||
let isValid = true;
|
let isFieldValid = true;
|
||||||
let fieldValueDate;
|
let fieldValueDate;
|
||||||
|
|
||||||
if (typeof field.value === 'string') {
|
if (typeof field.value === 'string') {
|
||||||
@@ -383,9 +384,9 @@ export class MaxDateTimeFieldValidator implements FormFieldValidator {
|
|||||||
if (fieldValueDate.isAfter(max)) {
|
if (fieldValueDate.isAfter(max)) {
|
||||||
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`;
|
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`;
|
||||||
field.validationSummary.attributes.set('maxValue', max.format(field.dateDisplayFormat).replace(':', '-'));
|
field.validationSummary.attributes.set('maxValue', max.format(field.dateDisplayFormat).replace(':', '-'));
|
||||||
isValid = false;
|
isFieldValid = false;
|
||||||
}
|
}
|
||||||
return isValid;
|
return isFieldValid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,3 +584,39 @@ export const FORM_FIELD_VALIDATORS = [
|
|||||||
new MinDateTimeFieldValidator(),
|
new MinDateTimeFieldValidator(),
|
||||||
new MaxDateTimeFieldValidator()
|
new MaxDateTimeFieldValidator()
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const momentToDateFnsMap = {
|
||||||
|
M: 'M',
|
||||||
|
D: 'd',
|
||||||
|
Y: 'y',
|
||||||
|
A: 'a'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const dateFnsToMomentMap = {
|
||||||
|
M: 'M',
|
||||||
|
d: 'D',
|
||||||
|
y: 'Y',
|
||||||
|
a: 'A'
|
||||||
|
};
|
||||||
|
|
||||||
|
export function convertMomentToDateFnsFormat(dateDisplayFormat: string): string {
|
||||||
|
for (const [search, replace] of Object.entries(momentToDateFnsMap)) {
|
||||||
|
dateDisplayFormat = dateDisplayFormat.replace(new RegExp(search, 'g'), replace);
|
||||||
|
}
|
||||||
|
return dateDisplayFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertDateFnsToMomentFormat(dateDisplayFormat: string): string {
|
||||||
|
for (const [search, replace] of Object.entries(dateFnsToMomentMap)) {
|
||||||
|
dateDisplayFormat = dateDisplayFormat.replace(new RegExp(search, 'g'), replace);
|
||||||
|
}
|
||||||
|
return dateDisplayFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatUpdate(date: number|Date, dateFormat: string): string {
|
||||||
|
return format(date, convertMomentToDateFnsFormat(dateFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseUpdate(value: string, dateFormat: string, date = new Date()): Date {
|
||||||
|
return parse(value, convertMomentToDateFnsFormat(dateFormat), date);
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,9 +19,16 @@ import moment from 'moment';
|
|||||||
import { FormFieldTypes } from './form-field-types';
|
import { FormFieldTypes } from './form-field-types';
|
||||||
import { FormFieldModel } from './form-field.model';
|
import { FormFieldModel } from './form-field.model';
|
||||||
import { FormModel } from './form.model';
|
import { FormModel } from './form.model';
|
||||||
|
import { DateFormatTranslationService } from '../../../public-api';
|
||||||
|
|
||||||
describe('FormFieldModel', () => {
|
describe('FormFieldModel', () => {
|
||||||
|
|
||||||
|
let dateFormatTranslationService: DateFormatTranslationService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
dateFormatTranslationService = new DateFormatTranslationService();
|
||||||
|
});
|
||||||
|
|
||||||
it('should store the form reference', () => {
|
it('should store the form reference', () => {
|
||||||
const form = new FormModel();
|
const form = new FormModel();
|
||||||
const model = new FormFieldModel(form);
|
const model = new FormFieldModel(form);
|
||||||
@@ -273,9 +280,9 @@ describe('FormFieldModel', () => {
|
|||||||
dateDisplayFormat: 'DD-MM-YYYY'
|
dateDisplayFormat: 'DD-MM-YYYY'
|
||||||
});
|
});
|
||||||
|
|
||||||
const currentDate = moment(new Date());
|
const currentDate = new Date();
|
||||||
const expectedDate = moment(currentDate).format('DD-MM-YYYY');
|
const expectedDate = dateFormatTranslationService.format(currentDate, 'DD-MM-YYYY');
|
||||||
const expectedDateFormat = `${currentDate.format('YYYY-MM-DD')}T00:00:00.000Z`;
|
const expectedDateFormat = `${dateFormatTranslationService.format(currentDate, 'YYYY-MM-DD')}T00:00:00.000Z`;
|
||||||
|
|
||||||
expect(field.value).toBe(expectedDate);
|
expect(field.value).toBe(expectedDate);
|
||||||
expect(form.values['ddmmyyy']).toEqual(expectedDateFormat);
|
expect(form.values['ddmmyyy']).toEqual(expectedDateFormat);
|
||||||
|
|||||||
@@ -29,15 +29,20 @@ import { ProcessFormModel } from './process-form-model.interface';
|
|||||||
import { isNumberValue } from './form-field-utils';
|
import { isNumberValue } from './form-field-utils';
|
||||||
import { VariableConfig } from './form-field-variable-options';
|
import { VariableConfig } from './form-field-variable-options';
|
||||||
import { DataColumn } from '../../../../datatable/data/data-column.model';
|
import { DataColumn } from '../../../../datatable/data/data-column.model';
|
||||||
|
import { isValid } from 'date-fns';
|
||||||
|
import { DateFormatTranslationService } from '../../../services/date-format-translation.service';
|
||||||
|
|
||||||
// Maps to FormFieldRepresentation
|
// Maps to FormFieldRepresentation
|
||||||
|
|
||||||
|
export const dateFormatTranslationService = new DateFormatTranslationService();
|
||||||
|
|
||||||
export class FormFieldModel extends FormWidgetModel {
|
export class FormFieldModel extends FormWidgetModel {
|
||||||
private _value: string;
|
private _value: string;
|
||||||
private _readOnly: boolean = false;
|
private _readOnly: boolean = false;
|
||||||
private _isValid: boolean = true;
|
private _isValid: boolean = true;
|
||||||
private _required: boolean = false;
|
private _required: boolean = false;
|
||||||
|
|
||||||
readonly defaultDateFormat: string = 'D-M-YYYY';
|
readonly defaultDateFormat: string = 'd-M-yyyy';
|
||||||
readonly defaultDateTimeFormat: string = 'D-M-YYYY hh:mm A';
|
readonly defaultDateTimeFormat: string = 'D-M-YYYY hh:mm A';
|
||||||
|
|
||||||
// model members
|
// model members
|
||||||
@@ -239,6 +244,15 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getDefaultDateFormat(jsonField: any): string {
|
private getDefaultDateFormat(jsonField: any): string {
|
||||||
|
if(jsonField.fields) {
|
||||||
|
Object.keys(jsonField.fields).forEach((el) => {
|
||||||
|
if(jsonField.fields[el]) {
|
||||||
|
jsonField.fields[el].forEach((element) => {
|
||||||
|
element.dateDisplayFormat = element.dateDisplayFormat? dateFormatTranslationService.convertMomentToDateFnsFormat(element.dateDisplayFormat): element.dateDisplayFormat;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
let originalType = jsonField.type;
|
let originalType = jsonField.type;
|
||||||
if (FormFieldTypes.isReadOnlyType(jsonField.type) && jsonField.params && jsonField.params.field) {
|
if (FormFieldTypes.isReadOnlyType(jsonField.type) && jsonField.params && jsonField.params.field) {
|
||||||
originalType = jsonField.params.field.type;
|
originalType = jsonField.params.field.type;
|
||||||
@@ -335,13 +349,13 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
This is needed due to Activiti displaying/editing dates in d-M-YYYY format
|
This is needed due to Activiti displaying/editing dates in d-M-YYYY format
|
||||||
but storing on server in ISO8601 format (i.e. 2013-02-04T22:44:30.652Z)
|
but storing on server in ISO8601 format (i.e. 2013-02-04T22:44:30.652Z)
|
||||||
*/
|
*/
|
||||||
if (this.isDateField(json) || this.isDateTimeField(json)) {
|
if (this.isDateTimeField(json)) {
|
||||||
if (value) {
|
if (value) {
|
||||||
let dateValue;
|
let dateValue;
|
||||||
if (isNumberValue(value)) {
|
if (isNumberValue(value)) {
|
||||||
dateValue = moment(value);
|
dateValue = moment(value);
|
||||||
} else {
|
} else {
|
||||||
dateValue = this.isDateTimeField(json) ? moment.utc(value, 'YYYY-MM-DD hh:mm A') : moment.utc(value.split('T')[0], 'YYYY-M-D');
|
dateValue = moment.utc(value, 'YYYY-MM-DD hh:mm A');
|
||||||
}
|
}
|
||||||
if (dateValue?.isValid()) {
|
if (dateValue?.isValid()) {
|
||||||
value = dateValue.utc().format(this.dateDisplayFormat);
|
value = dateValue.utc().format(this.dateDisplayFormat);
|
||||||
@@ -349,6 +363,20 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isDateField(json)) {
|
||||||
|
if (value) {
|
||||||
|
let dateValue;
|
||||||
|
if (isNumberValue(value)) {
|
||||||
|
dateValue = new Date(value);
|
||||||
|
} else {
|
||||||
|
dateValue = dateFormatTranslationService.parse(value.split('T')[0], 'YYYY-M-D');
|
||||||
|
}
|
||||||
|
if (isValid(dateValue)) {
|
||||||
|
value = dateFormatTranslationService.format(dateValue, this.dateDisplayFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isCheckboxField(json)) {
|
if (this.isCheckboxField(json)) {
|
||||||
value = json.value === 'true' || json.value === true;
|
value = json.value === 'true' || json.value === true;
|
||||||
}
|
}
|
||||||
@@ -417,12 +445,13 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
}
|
}
|
||||||
case FormFieldTypes.DATE: {
|
case FormFieldTypes.DATE: {
|
||||||
if (typeof this.value === 'string' && this.value === 'today') {
|
if (typeof this.value === 'string' && this.value === 'today') {
|
||||||
this.value = moment(new Date()).format(this.dateDisplayFormat);
|
this.value = dateFormatTranslationService.format(new Date(), this.dateDisplayFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dateValue = moment(this.value, this.dateDisplayFormat, true);
|
const dateValue = dateFormatTranslationService.parse(this.value, this.dateDisplayFormat);
|
||||||
if (dateValue?.isValid()) {
|
|
||||||
this.form.values[this.id] = `${dateValue.format('YYYY-MM-DD')}T00:00:00.000Z`;
|
if (isValid(dateValue)) {
|
||||||
|
this.form.values[this.id] = `${dateFormatTranslationService.format(dateValue, 'YYYY-MM-DD')}T00:00:00.000Z`;
|
||||||
} else {
|
} else {
|
||||||
this.form.values[this.id] = null;
|
this.form.values[this.id] = null;
|
||||||
this._value = this.value;
|
this._value = this.value;
|
||||||
|
|||||||
@@ -16,13 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import moment from 'moment';
|
|
||||||
import { FormFieldModel } from '../core/form-field.model';
|
import { FormFieldModel } from '../core/form-field.model';
|
||||||
import { FormModel } from '../core/form.model';
|
import { FormModel } from '../core/form.model';
|
||||||
import { DateWidgetComponent } from './date.widget';
|
import { DateWidgetComponent } from './date.widget';
|
||||||
import { CoreTestingModule } from '../../../../testing/core.testing.module';
|
import { CoreTestingModule } from '../../../../testing/core.testing.module';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { FormFieldTypes } from '../core/form-field-types';
|
import { FormFieldTypes } from '../core/form-field-types';
|
||||||
|
import { format, isSameDay, parse } from 'date-fns';
|
||||||
|
|
||||||
describe('DateWidgetComponent', () => {
|
describe('DateWidgetComponent', () => {
|
||||||
let widget: DateWidgetComponent;
|
let widget: DateWidgetComponent;
|
||||||
@@ -62,8 +62,9 @@ describe('DateWidgetComponent', () => {
|
|||||||
|
|
||||||
widget.ngOnInit();
|
widget.ngOnInit();
|
||||||
|
|
||||||
const expected = moment(minValue, widget.field.dateDisplayFormat);
|
const expected = parse(minValue, widget.field.dateDisplayFormat, new Date());
|
||||||
expect(widget.minDate.isSame(expected)).toBeTruthy();
|
const widgetDate = parse(widget.minDate, widget.field.dateDisplayFormat, new Date());
|
||||||
|
expect(isSameDay(widgetDate, expected)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should date field be present', () => {
|
it('should date field be present', () => {
|
||||||
@@ -85,8 +86,9 @@ describe('DateWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
widget.ngOnInit();
|
widget.ngOnInit();
|
||||||
|
|
||||||
const expected = moment(maxValue, widget.field.dateDisplayFormat);
|
const expected = parse(maxValue, widget.field.dateDisplayFormat, new Date());
|
||||||
expect(widget.maxDate.isSame(expected)).toBeTruthy();
|
const widgetDate = parse(widget.maxDate, widget.field.dateDisplayFormat, new Date());
|
||||||
|
expect(isSameDay(widgetDate, expected)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should eval visibility on date changed', () => {
|
it('should eval visibility on date changed', () => {
|
||||||
|
|||||||
@@ -32,8 +32,9 @@ import { MatDatepickerInputEvent } from '@angular/material/datepicker';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'date-widget',
|
selector: 'date-widget',
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: DateAdapter, useClass: MomentDateAdapter },
|
{ provide: DateAdapter, useClass: DateFnsAdapter },
|
||||||
{ provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS }],
|
{ provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS }
|
||||||
|
],
|
||||||
templateUrl: './date.widget.html',
|
templateUrl: './date.widget.html',
|
||||||
host: {
|
host: {
|
||||||
'(click)': 'event($event)',
|
'(click)': 'event($event)',
|
||||||
@@ -62,8 +63,10 @@ export class DateWidgetComponent extends WidgetComponent implements OnInit, OnDe
|
|||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(public formService: FormService,
|
constructor(public formService: FormService,
|
||||||
private dateAdapter: DateAdapter<Moment>,
|
private dateAdapter: DateAdapter<DateFnsAdapter>,
|
||||||
private userPreferencesService: UserPreferencesService) {
|
private userPreferencesService: UserPreferencesService,
|
||||||
|
@Inject(MAT_DATE_FORMATS) private dateFormatConfig: MatDateFormats,
|
||||||
|
protected dateFormatTranslationService: DateFormatTranslationService) {
|
||||||
super(formService);
|
super(formService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,10 +74,9 @@ export class DateWidgetComponent extends WidgetComponent implements OnInit, OnDe
|
|||||||
this.userPreferencesService
|
this.userPreferencesService
|
||||||
.select(UserPreferenceValues.Locale)
|
.select(UserPreferenceValues.Locale)
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.subscribe(locale => this.dateAdapter.setLocale(locale));
|
.subscribe(locale => this.dateAdapter.setLocale(DateFnsUtils.getLocaleFromString(locale)));
|
||||||
|
|
||||||
const momentDateAdapter = this.dateAdapter as MomentDateAdapter;
|
this.dateFormatConfig.display.dateInput = this.field.dateDisplayFormat;
|
||||||
momentDateAdapter.overrideDisplayFormat = this.field.dateDisplayFormat;
|
|
||||||
|
|
||||||
if (this.field) {
|
if (this.field) {
|
||||||
if (this.field.minValue) {
|
if (this.field.minValue) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export * from './services/form-rendering.service';
|
|||||||
export * from './services/form.service';
|
export * from './services/form.service';
|
||||||
export * from './services/form-validation-service.interface';
|
export * from './services/form-validation-service.interface';
|
||||||
export * from './services/widget-visibility.service';
|
export * from './services/widget-visibility.service';
|
||||||
|
export * from './services/date-format-translation.service';
|
||||||
|
|
||||||
export * from './events';
|
export * from './events';
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { DateFormatTranslationService } from './date-format-translation.service';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { CoreTestingModule } from '../../testing/core.testing.module';
|
||||||
|
|
||||||
|
describe('DateFormatTranslationService', () => {
|
||||||
|
let service: DateFormatTranslationService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [TranslateModule.forRoot(), CoreTestingModule],
|
||||||
|
providers: [DateFormatTranslationService]
|
||||||
|
});
|
||||||
|
|
||||||
|
service = TestBed.inject(DateFormatTranslationService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert moment to date-fns format correctly', () => {
|
||||||
|
const momentFormat = 'YYYY-MM-DD';
|
||||||
|
const expectedDateFnsFormat = 'yyyy-MM-dd';
|
||||||
|
|
||||||
|
const result = service.convertMomentToDateFnsFormat(momentFormat);
|
||||||
|
|
||||||
|
expect(result).toBe(expectedDateFnsFormat);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert date-fns to moment format correctly', () => {
|
||||||
|
const dateFnsFormat = 'yyyy-MM-dd';
|
||||||
|
const expectedMomentFormat = 'YYYY-MM-DD';
|
||||||
|
|
||||||
|
const result = service.convertDateFnsToMomentFormat(dateFnsFormat);
|
||||||
|
|
||||||
|
expect(result).toBe(expectedMomentFormat);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should format a date correctly', () => {
|
||||||
|
const date = new Date('2023-09-22T12:00:00Z');
|
||||||
|
const dateFormat = 'yyyy-MM-dd';
|
||||||
|
const expectedFormattedDate = '2023-09-22';
|
||||||
|
|
||||||
|
const result = service.format(date, dateFormat);
|
||||||
|
|
||||||
|
expect(result).toBe(expectedFormattedDate);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse a date correctly', () => {
|
||||||
|
const dateString = '2023-09-22';
|
||||||
|
const dateFormat = 'yyyy-MM-dd';
|
||||||
|
const expectedParsedDate = new Date('2023-09-22T00:00:00Z');
|
||||||
|
|
||||||
|
const result = service.parse(dateString, dateFormat);
|
||||||
|
|
||||||
|
expect(result).toEqual(expectedParsedDate);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { format, parse } from 'date-fns';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class DateFormatTranslationService {
|
||||||
|
private momentToDateFnsMap = {
|
||||||
|
M: 'M',
|
||||||
|
D: 'd',
|
||||||
|
Y: 'y',
|
||||||
|
A: 'a'
|
||||||
|
};
|
||||||
|
|
||||||
|
private dateFnsToMomentMap = {
|
||||||
|
M: 'M',
|
||||||
|
d: 'D',
|
||||||
|
y: 'Y',
|
||||||
|
a: 'A'
|
||||||
|
};
|
||||||
|
|
||||||
|
convertMomentToDateFnsFormat(dateDisplayFormat: string): string {
|
||||||
|
for (const [search, replace] of Object.entries(this.momentToDateFnsMap)) {
|
||||||
|
dateDisplayFormat = dateDisplayFormat.replace(new RegExp(search, 'g'), replace);
|
||||||
|
}
|
||||||
|
return dateDisplayFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
convertDateFnsToMomentFormat(dateDisplayFormat: string): string {
|
||||||
|
for (const [search, replace] of Object.entries(this.dateFnsToMomentMap)) {
|
||||||
|
dateDisplayFormat = dateDisplayFormat.replace(new RegExp(search, 'g'), replace);
|
||||||
|
}
|
||||||
|
return dateDisplayFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
format(date: number|Date, dateFormat: string): string {
|
||||||
|
return format(date, this.convertMomentToDateFnsFormat(dateFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(value: string, dateFormat: string, date = new Date()): Date {
|
||||||
|
return parse(value, this.convertMomentToDateFnsFormat(dateFormat), date);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { CoreTestingModule } from '../testing/core.testing.module';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { DatePipe } from './date.pipe';
|
||||||
|
import { DateFormatTranslationService } from '../form/public-api';
|
||||||
|
|
||||||
|
describe('DatePipe', () => {
|
||||||
|
let datePipe: DatePipe;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [TranslateModule.forRoot(), CoreTestingModule],
|
||||||
|
providers: [DatePipe, DateFormatTranslationService]
|
||||||
|
});
|
||||||
|
datePipe = TestBed.inject(DatePipe);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the formatted date string when given a valid date object', () => {
|
||||||
|
const inputDate = new Date('2023-08-14');
|
||||||
|
const dateFormat = 'DD-MM-YYYY';
|
||||||
|
const expectedOutput = '14-08-2023';
|
||||||
|
|
||||||
|
const result = datePipe.transform(inputDate, dateFormat);
|
||||||
|
|
||||||
|
expect(result).toBe(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the input value when given an invalid date object', () => {
|
||||||
|
const inputDate = new Date('invalid');
|
||||||
|
const dateFormat = 'DD-MM-YYYY';
|
||||||
|
const expectedOutput = inputDate.toString();
|
||||||
|
|
||||||
|
const result = datePipe.transform(inputDate, dateFormat);
|
||||||
|
|
||||||
|
expect(result).toBe(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the formatted date string when given a valid date string', () => {
|
||||||
|
const inputDate = '2023-08-14';
|
||||||
|
const dateFormat = 'DD-MM-YYYY';
|
||||||
|
const expectedOutput = '14-08-2023';
|
||||||
|
|
||||||
|
const result = datePipe.transform(inputDate, dateFormat);
|
||||||
|
|
||||||
|
expect(result).toBe(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the input value when given an invalid date string', () => {
|
||||||
|
const inputDate = 'not_a_valid_date';
|
||||||
|
const dateFormat = 'DD-MM-YYYY';
|
||||||
|
const expectedOutput = inputDate;
|
||||||
|
|
||||||
|
const result = datePipe.transform(inputDate, dateFormat);
|
||||||
|
|
||||||
|
expect(result).toBe(expectedOutput);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
import { isValid } from 'date-fns';
|
||||||
|
import { DateFormatTranslationService } from '../form/services/date-format-translation.service';
|
||||||
|
|
||||||
|
@Pipe({ name: 'adfDate' })
|
||||||
|
export class DatePipe implements PipeTransform {
|
||||||
|
constructor(private dateFormatTranslationService: DateFormatTranslationService) {}
|
||||||
|
|
||||||
|
transform(value: Date | string, dateFormat: string): string {
|
||||||
|
const date = value instanceof Date ? value : new Date(value);
|
||||||
|
return isValid(date) ? this.dateFormatTranslationService.format(date, dateFormat) : value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ import { MomentDateTimePipe } from './moment-datetime.pipe';
|
|||||||
import { FilterStringPipe } from './filter-string.pipe';
|
import { FilterStringPipe } from './filter-string.pipe';
|
||||||
import { FilterOutArrayObjectsByPropPipe } from './filter-out-every-object-by-prop.pipe';
|
import { FilterOutArrayObjectsByPropPipe } from './filter-out-every-object-by-prop.pipe';
|
||||||
import { DateTimePipe } from './date-time.pipe';
|
import { DateTimePipe } from './date-time.pipe';
|
||||||
|
import { DatePipe } from './date.pipe';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -56,6 +57,7 @@ import { DateTimePipe } from './date-time.pipe';
|
|||||||
DecimalNumberPipe,
|
DecimalNumberPipe,
|
||||||
LocalizedRolePipe,
|
LocalizedRolePipe,
|
||||||
MomentDatePipe,
|
MomentDatePipe,
|
||||||
|
DatePipe,
|
||||||
MomentDateTimePipe,
|
MomentDateTimePipe,
|
||||||
DateTimePipe,
|
DateTimePipe,
|
||||||
FilterStringPipe,
|
FilterStringPipe,
|
||||||
@@ -74,6 +76,7 @@ import { DateTimePipe } from './date-time.pipe';
|
|||||||
DecimalNumberPipe,
|
DecimalNumberPipe,
|
||||||
LocalizedRolePipe,
|
LocalizedRolePipe,
|
||||||
MomentDatePipe,
|
MomentDatePipe,
|
||||||
|
DatePipe,
|
||||||
MomentDateTimePipe,
|
MomentDateTimePipe,
|
||||||
DateTimePipe,
|
DateTimePipe,
|
||||||
FilterStringPipe,
|
FilterStringPipe,
|
||||||
@@ -93,6 +96,7 @@ import { DateTimePipe } from './date-time.pipe';
|
|||||||
DecimalNumberPipe,
|
DecimalNumberPipe,
|
||||||
LocalizedRolePipe,
|
LocalizedRolePipe,
|
||||||
MomentDatePipe,
|
MomentDatePipe,
|
||||||
|
DatePipe,
|
||||||
MomentDateTimePipe,
|
MomentDateTimePipe,
|
||||||
DateTimePipe,
|
DateTimePipe,
|
||||||
FilterStringPipe,
|
FilterStringPipe,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export * from './user-initial.pipe';
|
|||||||
export * from './localized-role.pipe';
|
export * from './localized-role.pipe';
|
||||||
export * from './pipe.module';
|
export * from './pipe.module';
|
||||||
export * from './moment-date.pipe';
|
export * from './moment-date.pipe';
|
||||||
|
export * from './date.pipe';
|
||||||
export * from './moment-datetime.pipe';
|
export * from './moment-datetime.pipe';
|
||||||
export * from './date-time.pipe';
|
export * from './date-time.pipe';
|
||||||
export * from './filter-string.pipe';
|
export * from './filter-string.pipe';
|
||||||
|
|||||||
+4
-4
@@ -1,11 +1,11 @@
|
|||||||
<div class="{{field.className}}" id="data-widget" [class.adf-invalid]="!field.isValid && isTouched()" [class.adf-left-label-input-container]="field.leftLabels">
|
<div class="{{field.className}}" id="data-widget" [class.adf-invalid]="!field.isValid && isTouched()" [class.adf-left-label-input-container]="field.leftLabels">
|
||||||
<div *ngIf="field.leftLabels">
|
<div *ngIf="field.leftLabels">
|
||||||
<label class="adf-label adf-left-label" [attr.for]="field.id">{{field.name | translate }} ({{field.dateDisplayFormat}})<span class="adf-asterisk"
|
<label class="adf-label adf-left-label" [attr.for]="field.id">{{field.name | translate }} ({{dateFormatTranslationService.convertDateFnsToMomentFormat(field.dateDisplayFormat)}})<span class="adf-asterisk"
|
||||||
*ngIf="isRequired()">*</span></label>
|
*ngIf="isRequired()">*</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field class="adf-date-widget" [class.adf-left-label-input-datepicker]="field.leftLabels" [hideRequiredMarker]="true">
|
<mat-form-field class="adf-date-widget" [class.adf-left-label-input-datepicker]="field.leftLabels" [hideRequiredMarker]="true">
|
||||||
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">{{field.name | translate }} ({{field.dateDisplayFormat}})<span class="adf-asterisk"
|
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">{{field.name | translate }} ({{dateFormatTranslationService.convertDateFnsToMomentFormat(field.dateDisplayFormat)}})<span class="adf-asterisk"
|
||||||
*ngIf="isRequired()">*</span></label>
|
*ngIf="isRequired()">*</span></label>
|
||||||
<input matInput
|
<input matInput
|
||||||
[id]="field.id"
|
[id]="field.id"
|
||||||
@@ -22,11 +22,11 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<error-widget [error]="field.validationSummary"></error-widget>
|
<error-widget [error]="field.validationSummary"></error-widget>
|
||||||
<error-widget *ngIf="isInvalidFieldRequired() && isTouched()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
|
<error-widget *ngIf="isInvalidFieldRequired() && isTouched()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
|
||||||
<mat-datepicker #datePicker [touchUi]="true" [startAt]="field.value | adfMomentDate: field.dateDisplayFormat" [disabled]="field.readOnly"></mat-datepicker>
|
<mat-datepicker #datePicker [touchUi]="true" [startAt]="field.value | adfDate: field.dateDisplayFormat" [disabled]="field.readOnly"></mat-datepicker>
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
[matDatepicker]="datePicker"
|
[matDatepicker]="datePicker"
|
||||||
[value]="field.value | adfMomentDate: field.dateDisplayFormat"
|
[value]="field.value | adfDate: field.dateDisplayFormat"
|
||||||
[min]="minDate"
|
[min]="minDate"
|
||||||
[max]="maxDate"
|
[max]="maxDate"
|
||||||
[disabled]="field.readOnly"
|
[disabled]="field.readOnly"
|
||||||
|
|||||||
+18
-19
@@ -18,11 +18,11 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { DateCloudWidgetComponent } from './date-cloud.widget';
|
import { DateCloudWidgetComponent } from './date-cloud.widget';
|
||||||
import { FormFieldModel, FormModel, FormFieldTypes } from '@alfresco/adf-core';
|
import { FormFieldModel, FormModel, FormFieldTypes } from '@alfresco/adf-core';
|
||||||
import moment from 'moment';
|
|
||||||
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
|
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { DATE_FORMAT_CLOUD } from '../../../../models/date-format-cloud.model';
|
import { DATE_FORMAT_CLOUD } from '../../../../models/date-format-cloud.model';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { addDays, format, subDays } from 'date-fns';
|
||||||
|
|
||||||
describe('DateWidgetComponent', () => {
|
describe('DateWidgetComponent', () => {
|
||||||
|
|
||||||
@@ -52,8 +52,8 @@ describe('DateWidgetComponent', () => {
|
|||||||
|
|
||||||
widget.ngOnInit();
|
widget.ngOnInit();
|
||||||
|
|
||||||
const expected = moment(minValue, DATE_FORMAT_CLOUD);
|
const expected = format(new Date(minValue), DATE_FORMAT_CLOUD);
|
||||||
expect(widget.minDate.isSame(expected)).toBeTruthy();
|
expect(widget.minDate).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should date field be present', () => {
|
it('should date field be present', () => {
|
||||||
@@ -75,8 +75,8 @@ describe('DateWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
widget.ngOnInit();
|
widget.ngOnInit();
|
||||||
|
|
||||||
const expected = moment(maxValue, DATE_FORMAT_CLOUD);
|
const expected = format(new Date(maxValue), DATE_FORMAT_CLOUD);
|
||||||
expect(widget.maxDate.isSame(expected)).toBeTruthy();
|
expect(widget.maxDate).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should eval visibility on date changed', () => {
|
it('should eval visibility on date changed', () => {
|
||||||
@@ -91,8 +91,8 @@ describe('DateWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
widget.field = field;
|
widget.field = field;
|
||||||
const todayDate = moment().format(DATE_FORMAT_CLOUD);
|
const todayDate = new Date();
|
||||||
widget.onDateChanged({ value: todayDate });
|
widget.onDateChanged({ value: format(todayDate, DATE_FORMAT_CLOUD) });
|
||||||
|
|
||||||
expect(widget.onFieldChanged).toHaveBeenCalledWith(field);
|
expect(widget.onFieldChanged).toHaveBeenCalledWith(field);
|
||||||
});
|
});
|
||||||
@@ -293,8 +293,8 @@ describe('DateWidgetComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
const todayDate = moment().format(DATE_FORMAT_CLOUD);
|
const todayDate = new Date();
|
||||||
const expected = moment(todayDate).subtract(widget.field.minDateRangeValue, 'days');
|
const expected = format(subDays(todayDate, widget.field.minDateRangeValue), DATE_FORMAT_CLOUD);
|
||||||
expect(widget.minDate).toEqual(expected);
|
expect(widget.minDate).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -343,8 +343,8 @@ describe('DateWidgetComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
const todayDate = moment().format(DATE_FORMAT_CLOUD);
|
const todayDate = new Date();
|
||||||
const expected = moment(todayDate).add(widget.field.maxDateRangeValue, 'days');
|
const expected = format(addDays(todayDate, widget.field.maxDateRangeValue), DATE_FORMAT_CLOUD);
|
||||||
expect(widget.maxDate).toEqual(expected);
|
expect(widget.maxDate).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -392,7 +392,6 @@ describe('DateWidgetComponent', () => {
|
|||||||
|
|
||||||
describe('check date validation by dynamic date ranges', () => {
|
describe('check date validation by dynamic date ranges', () => {
|
||||||
it('should minValue be equal to today date minus minDateRangeValue', async () => {
|
it('should minValue be equal to today date minus minDateRangeValue', async () => {
|
||||||
spyOn(widget, 'getTodaysFormattedDate').and.returnValue('2022-07-22');
|
|
||||||
widget.field = new FormFieldModel(null, {
|
widget.field = new FormFieldModel(null, {
|
||||||
dynamicDateRangeSelection: true,
|
dynamicDateRangeSelection: true,
|
||||||
maxDateRangeValue: null,
|
maxDateRangeValue: null,
|
||||||
@@ -404,7 +403,8 @@ describe('DateWidgetComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
const expectedMinValueString = '2022-07-21';
|
const currentDate = new Date();
|
||||||
|
const expectedMinValueString = format(subDays(currentDate, 1), DATE_FORMAT_CLOUD);
|
||||||
|
|
||||||
expect(widget.field.minValue).toEqual(expectedMinValueString);
|
expect(widget.field.minValue).toEqual(expectedMinValueString);
|
||||||
expect(widget.maxDate).toBeUndefined();
|
expect(widget.maxDate).toBeUndefined();
|
||||||
@@ -412,7 +412,6 @@ describe('DateWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should maxValue be equal to today date plus maxDateRangeValue', async () => {
|
it('should maxValue be equal to today date plus maxDateRangeValue', async () => {
|
||||||
spyOn(widget, 'getTodaysFormattedDate').and.returnValue('2022-07-22');
|
|
||||||
widget.field = new FormFieldModel(null, {
|
widget.field = new FormFieldModel(null, {
|
||||||
dynamicDateRangeSelection: true,
|
dynamicDateRangeSelection: true,
|
||||||
maxDateRangeValue: 8,
|
maxDateRangeValue: 8,
|
||||||
@@ -424,7 +423,8 @@ describe('DateWidgetComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
const expectedMaxValueString = '2022-07-30';
|
const currentDate = new Date();
|
||||||
|
const expectedMaxValueString = format(addDays(currentDate, 8), DATE_FORMAT_CLOUD);
|
||||||
|
|
||||||
expect(widget.field.maxValue).toEqual(expectedMaxValueString);
|
expect(widget.field.maxValue).toEqual(expectedMaxValueString);
|
||||||
expect(widget.minDate).toBeUndefined();
|
expect(widget.minDate).toBeUndefined();
|
||||||
@@ -432,7 +432,6 @@ describe('DateWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should maxValue and minValue be null if maxDateRangeValue and minDateRangeValue are null', async () => {
|
it('should maxValue and minValue be null if maxDateRangeValue and minDateRangeValue are null', async () => {
|
||||||
spyOn(widget, 'getTodaysFormattedDate').and.returnValue('2022-07-22');
|
|
||||||
widget.field = new FormFieldModel(null, {
|
widget.field = new FormFieldModel(null, {
|
||||||
dynamicDateRangeSelection: true,
|
dynamicDateRangeSelection: true,
|
||||||
maxDateRangeValue: null,
|
maxDateRangeValue: null,
|
||||||
@@ -451,7 +450,6 @@ describe('DateWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should maxValue and minValue not be null if maxDateRangeVale and minDateRangeValue are not null', async () => {
|
it('should maxValue and minValue not be null if maxDateRangeVale and minDateRangeValue are not null', async () => {
|
||||||
spyOn(widget, 'getTodaysFormattedDate').and.returnValue('2022-07-22');
|
|
||||||
widget.field = new FormFieldModel(null, {
|
widget.field = new FormFieldModel(null, {
|
||||||
dynamicDateRangeSelection: true,
|
dynamicDateRangeSelection: true,
|
||||||
maxDateRangeValue: 8,
|
maxDateRangeValue: 8,
|
||||||
@@ -463,8 +461,9 @@ describe('DateWidgetComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
const expectedMaxValueString = '2022-07-30';
|
const currentDate = new Date();
|
||||||
const expectedMinValueString = '2022-07-12';
|
const expectedMaxValueString = format(addDays(currentDate, 8), DATE_FORMAT_CLOUD);
|
||||||
|
const expectedMinValueString = format(subDays(currentDate, 10), DATE_FORMAT_CLOUD);
|
||||||
|
|
||||||
expect(widget.field.maxValue).toEqual(expectedMaxValueString);
|
expect(widget.field.maxValue).toEqual(expectedMaxValueString);
|
||||||
expect(widget.field.minValue).toEqual(expectedMinValueString);
|
expect(widget.field.minValue).toEqual(expectedMinValueString);
|
||||||
|
|||||||
+26
-28
@@ -17,22 +17,23 @@
|
|||||||
|
|
||||||
/* eslint-disable @angular-eslint/component-selector */
|
/* eslint-disable @angular-eslint/component-selector */
|
||||||
|
|
||||||
import { Component, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core';
|
import { Component, OnInit, ViewEncapsulation, OnDestroy, Inject } from '@angular/core';
|
||||||
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
|
import { DateAdapter, MAT_DATE_FORMATS, MatDateFormats } from '@angular/material/core';
|
||||||
import moment, { Moment } from 'moment';
|
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
MOMENT_DATE_FORMATS, MomentDateAdapter, WidgetComponent,
|
WidgetComponent,
|
||||||
UserPreferencesService, UserPreferenceValues, FormService
|
UserPreferencesService, UserPreferenceValues, FormService, DateFormatTranslationService, DateFnsUtils
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { DATE_FORMAT_CLOUD } from '../../../../models/date-format-cloud.model';
|
import { DATE_FORMAT_CLOUD } from '../../../../models/date-format-cloud.model';
|
||||||
|
import { DateFnsAdapter, MAT_DATE_FNS_FORMATS } from '@angular/material-date-fns-adapter';
|
||||||
|
import { addDays, isValid, subDays } from 'date-fns';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'date-widget',
|
selector: 'date-widget',
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: DateAdapter, useClass: MomentDateAdapter },
|
{ provide: DateAdapter, useClass: DateFnsAdapter },
|
||||||
{ provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS }],
|
{ provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS }],
|
||||||
templateUrl: './date-cloud.widget.html',
|
templateUrl: './date-cloud.widget.html',
|
||||||
styleUrls: ['./date-cloud.widget.scss'],
|
styleUrls: ['./date-cloud.widget.scss'],
|
||||||
host: {
|
host: {
|
||||||
@@ -51,14 +52,16 @@ import { DATE_FORMAT_CLOUD } from '../../../../models/date-format-cloud.model';
|
|||||||
export class DateCloudWidgetComponent extends WidgetComponent implements OnInit, OnDestroy {
|
export class DateCloudWidgetComponent extends WidgetComponent implements OnInit, OnDestroy {
|
||||||
typeId = 'DateCloudWidgetComponent';
|
typeId = 'DateCloudWidgetComponent';
|
||||||
|
|
||||||
minDate: Moment;
|
minDate: string;
|
||||||
maxDate: Moment;
|
maxDate: string;
|
||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(public formService: FormService,
|
constructor(public formService: FormService,
|
||||||
private dateAdapter: DateAdapter<Moment>,
|
private dateAdapter: DateAdapter<DateFnsAdapter>,
|
||||||
private userPreferencesService: UserPreferencesService) {
|
private userPreferencesService: UserPreferencesService,
|
||||||
|
@Inject(MAT_DATE_FORMATS) private dateFormatConfig: MatDateFormats,
|
||||||
|
protected dateFormatTranslationService: DateFormatTranslationService) {
|
||||||
super(formService);
|
super(formService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,47 +69,42 @@ export class DateCloudWidgetComponent extends WidgetComponent implements OnInit,
|
|||||||
this.userPreferencesService
|
this.userPreferencesService
|
||||||
.select(UserPreferenceValues.Locale)
|
.select(UserPreferenceValues.Locale)
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.subscribe(locale => this.dateAdapter.setLocale(locale));
|
.subscribe(locale => this.dateAdapter.setLocale(DateFnsUtils.getLocaleFromString(locale)));
|
||||||
|
|
||||||
const momentDateAdapter = this.dateAdapter as MomentDateAdapter;
|
this.dateFormatConfig.display.dateInput = this.field.dateDisplayFormat;
|
||||||
momentDateAdapter.overrideDisplayFormat = this.field.dateDisplayFormat;
|
|
||||||
|
|
||||||
if (this.field) {
|
if (this.field) {
|
||||||
if (this.field.dynamicDateRangeSelection) {
|
if (this.field.dynamicDateRangeSelection) {
|
||||||
const today = this.getTodaysFormattedDate();
|
const today = new Date();
|
||||||
if (Number.isInteger(this.field.minDateRangeValue)) {
|
if (Number.isInteger(this.field.minDateRangeValue)) {
|
||||||
this.minDate = moment(today).subtract(this.field.minDateRangeValue, 'days');
|
this.minDate = this.dateFormatTranslationService.format(subDays(today, this.field.minDateRangeValue), DATE_FORMAT_CLOUD);
|
||||||
this.field.minValue = this.minDate.format(DATE_FORMAT_CLOUD);
|
this.field.minValue = this.minDate;
|
||||||
}
|
}
|
||||||
if (Number.isInteger(this.field.maxDateRangeValue)) {
|
if (Number.isInteger(this.field.maxDateRangeValue)) {
|
||||||
this.maxDate = moment(today).add(this.field.maxDateRangeValue, 'days');
|
this.maxDate = this.dateFormatTranslationService.format(addDays(today, this.field.maxDateRangeValue), DATE_FORMAT_CLOUD);
|
||||||
this.field.maxValue = this.maxDate.format(DATE_FORMAT_CLOUD);
|
this.field.maxValue = this.maxDate;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.field.minValue) {
|
if (this.field.minValue) {
|
||||||
this.minDate = moment(this.field.minValue, DATE_FORMAT_CLOUD);
|
this.minDate = this.dateFormatTranslationService.format(new Date(this.field.minValue), DATE_FORMAT_CLOUD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.field.maxValue) {
|
if (this.field.maxValue) {
|
||||||
this.maxDate = moment(this.field.maxValue, DATE_FORMAT_CLOUD);
|
this.maxDate = this.dateFormatTranslationService.format(new Date(this.field.maxValue), DATE_FORMAT_CLOUD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getTodaysFormattedDate() {
|
|
||||||
return moment().format(DATE_FORMAT_CLOUD);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.onDestroy$.next(true);
|
this.onDestroy$.next(true);
|
||||||
this.onDestroy$.complete();
|
this.onDestroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
onDateChanged(newDateValue) {
|
onDateChanged(newDateValue) {
|
||||||
const date = moment(newDateValue, this.field.dateDisplayFormat, true);
|
const date = new Date(newDateValue);
|
||||||
if (date.isValid()) {
|
if (isValid(date)) {
|
||||||
this.field.value = date.format(this.field.dateDisplayFormat);
|
this.field.value = this.dateFormatTranslationService.format(date, this.field.dateDisplayFormat);
|
||||||
} else {
|
} else {
|
||||||
this.field.value = newDateValue;
|
this.field.value = newDateValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,4 +15,4 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const DATE_FORMAT_CLOUD = 'YYYY-MM-DD';
|
export const DATE_FORMAT_CLOUD = 'yyyy-MM-dd';
|
||||||
|
|||||||
Reference in New Issue
Block a user