From b2e40162c6c414ef1a70bcebd07ffa1c37f78a00 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 29 Sep 2016 16:07:26 +0100 Subject: [PATCH] #632 date widget (basic implementation) --- demo-shell-ng2/index.html | 1 + demo-shell-ng2/package.json | 2 + ng2-components/ng2-activiti-form/package.json | 4 +- .../widgets/container/container.widget.html | 3 + .../widgets/core/form-field-types.ts | 1 + .../widgets/core/form-field-validator.ts | 102 ++++++++++++++++++ .../widgets/core/form-field.model.ts | 32 +++++- .../components/widgets/date/date.widget.css | 19 ++++ .../components/widgets/date/date.widget.html | 12 +++ .../components/widgets/date/date.widget.ts | 52 +++++++++ .../src/components/widgets/index.ts | 5 +- 11 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.css create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.html create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.ts diff --git a/demo-shell-ng2/index.html b/demo-shell-ng2/index.html index bb2bb3260f..986e63bc43 100644 --- a/demo-shell-ng2/index.html +++ b/demo-shell-ng2/index.html @@ -19,6 +19,7 @@ + diff --git a/demo-shell-ng2/package.json b/demo-shell-ng2/package.json index 02596c56c8..1a9a61e77d 100644 --- a/demo-shell-ng2/package.json +++ b/demo-shell-ng2/package.json @@ -73,6 +73,8 @@ "pdfjs-dist": "1.5.404", "flag-icon-css": "2.3.0", "intl": "1.2.4", + "moment": "2.15.1", + "alfresco-js-api": "^0.3.0", "ng2-alfresco-core": "0.3.2", "ng2-alfresco-datatable": "0.3.2", diff --git a/ng2-components/ng2-activiti-form/package.json b/ng2-components/ng2-activiti-form/package.json index df2f23f0d0..2aeb209cfe 100644 --- a/ng2-components/ng2-activiti-form/package.json +++ b/ng2-components/ng2-activiti-form/package.json @@ -60,8 +60,10 @@ "systemjs": "0.19.27", "zone.js": "^0.6.23", - "alfresco-js-api": "^0.3.0", "ng2-translate": "2.5.0", + "moment": "2.15.1", + + "alfresco-js-api": "^0.3.0", "ng2-alfresco-core": "0.3.2" }, "devDependencies": { diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/container/container.widget.html b/ng2-components/ng2-activiti-form/src/components/widgets/container/container.widget.html index bc22014766..49c5f5dce7 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/container/container.widget.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/container/container.widget.html @@ -56,6 +56,9 @@
+
+ +
UNKNOWN WIDGET TYPE: {{field.type}}
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-types.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-types.ts index 4884865bc2..2c06b4bb17 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-types.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-types.ts @@ -31,6 +31,7 @@ export class FormFieldTypes { static PEOPLE: string = 'people'; static BOOLEAN: string = 'boolean'; static NUMBER: string = 'integer'; + static DATE: string = 'date'; static READONLY_TYPES: string[] = [ FormFieldTypes.HYPERLINK, diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-validator.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-validator.ts index 7a483c1294..c8170892e3 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-validator.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-validator.ts @@ -18,6 +18,8 @@ import { FormFieldModel } from './form-field.model'; import { FormFieldTypes } from './form-field-types'; +declare var moment: any; + export interface FormFieldValidator { isSupported(field: FormFieldModel): boolean; @@ -107,6 +109,106 @@ export class NumberFieldValidator implements FormFieldValidator { } } +export class DateFieldValidator implements FormFieldValidator { + + private supportedTypes = [ + FormFieldTypes.DATE + ]; + + // Validates that the input string is a valid date formatted as (default D-M-YYYY) + static isValidDate(dateString: string, dateFormat: string = 'D-M-YYYY'): boolean { + if (dateString) { + let d = moment(dateString.split('T')[0], dateFormat, true); + return d.isValid(); + } + + return false; + } + + isSupported(field: FormFieldModel): boolean { + return field && this.supportedTypes.indexOf(field.type) > -1; + } + + validate(field: FormFieldModel): boolean { + if (this.isSupported(field) && field.value) { + if (DateFieldValidator.isValidDate(field.value)) { + return true; + } + field.validationSummary = 'Invalid date format'; + return false; + } + return true; + } +} + +export class MinDateFieldValidator implements FormFieldValidator { + + private supportedTypes = [ + FormFieldTypes.DATE + ]; + + isSupported(field: FormFieldModel): boolean { + return field && + this.supportedTypes.indexOf(field.type) > -1 && + !!field.minValue; + } + + validate(field: FormFieldModel): boolean { + if (this.isSupported(field) && field.value) { + const dateFormat = 'D-M-YYYY'; + + if (!DateFieldValidator.isValidDate(field.value, dateFormat)) { + field.validationSummary = 'Invalid date format'; + return false; + } + + // remove time and timezone info + let d = moment(field.value.split('T')[0], dateFormat); + let min = moment(field.minValue, dateFormat); + + if (d.isBefore(min)) { + field.validationSummary = `Should not be less than ${field.minValue}`; + return false; + } + } + return true; + } +} + +export class MaxDateFieldValidator implements FormFieldValidator { + + private supportedTypes = [ + FormFieldTypes.DATE + ]; + + isSupported(field: FormFieldModel): boolean { + return field && + this.supportedTypes.indexOf(field.type) > -1 && + !!field.maxValue; + } + + validate(field: FormFieldModel): boolean { + if (this.isSupported(field) && field.value) { + const dateFormat = 'D-M-YYYY'; + + if (!DateFieldValidator.isValidDate(field.value, dateFormat)) { + field.validationSummary = 'Invalid date format'; + return false; + } + + // remove time and timezone info + let d = moment(field.value.split('T')[0], dateFormat); + var max = moment(field.maxValue, dateFormat); + + if (d.isAfter(max)) { + field.validationSummary = `Should not be greater than ${field.maxValue}`; + return false; + } + } + return true; + } +} + export class MinLengthFieldValidator implements FormFieldValidator { private supportedTypes = [ diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field.model.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field.model.ts index 1e23b380cb..ae71b5b30f 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field.model.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field.model.ts @@ -29,9 +29,13 @@ import { MaxLengthFieldValidator, MinValueFieldValidator, MaxValueFieldValidator, - RegExFieldValidator + RegExFieldValidator, + DateFieldValidator, + MinDateFieldValidator, + MaxDateFieldValidator } from './form-field-validator'; +declare var moment: any; export class FormFieldModel extends FormWidgetModel { @@ -152,7 +156,10 @@ export class FormFieldModel extends FormWidgetModel { new MaxLengthFieldValidator(), new MinValueFieldValidator(), new MaxValueFieldValidator(), - new RegExFieldValidator() + new RegExFieldValidator(), + new DateFieldValidator(), + new MinDateFieldValidator(), + new MaxDateFieldValidator() ]; this.updateForm(); @@ -191,6 +198,19 @@ export class FormFieldModel extends FormWidgetModel { } } + /* + This is needed due to Activiti desplaying/editing dates in d-M-YYYY format + but storing on server in ISO8601 format (i.e. 2013-02-04T22:44:30.652Z) + */ + if (json.type === FormFieldTypes.DATE) { + if (value) { + let d = moment(value.split('T')[0]); + if (d.isValid()) { + value = d.format('D-M-YYYY'); + } + } + } + return value; } @@ -241,6 +261,14 @@ export class FormFieldModel extends FormWidgetModel { this.form.values[this.id] = null; } break; + case FormFieldTypes.DATE: + let d = moment(this.value, 'D-M-YYYY'); + if (d.isValid()) { + this.form.values[this.id] = `${d.format('YYYY-MM-DD')}T00:00:00.000Z`; + } else { + this.form.values[this.id] = null; + } + break; default: if (!FormFieldTypes.isReadOnlyType(this.type)) { this.form.values[this.id] = this.value; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.css b/ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.css new file mode 100644 index 0000000000..48a6b82b45 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.css @@ -0,0 +1,19 @@ +.date-widget { + width: 100%; +} + +.date-widget__invalid .mdl-textfield__input { + border-color: #d50000; +} + +.date-widget__invalid .mdl-textfield__label { + color: #d50000; +} + +.date-widget__invalid .mdl-textfield__label:after { + background-color: #d50000; +} + +.date-widget__invalid .mdl-textfield__error { + visibility: visible !important; +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.html b/ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.html new file mode 100644 index 0000000000..93177998e1 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.html @@ -0,0 +1,12 @@ +
+ + + {{field.validationSummary}} +
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.ts b/ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.ts new file mode 100644 index 0000000000..3348865043 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/date/date.widget.ts @@ -0,0 +1,52 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * 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 { Component, ElementRef } from '@angular/core'; +import { WidgetComponent } from './../widget.component'; + +declare let __moduleName: string; + +@Component({ + moduleId: __moduleName, + selector: 'date-widget', + templateUrl: './date.widget.html', + styleUrls: ['./date.widget.css'] +}) +export class DateWidget extends WidgetComponent { + + constructor(private elementRef: ElementRef) { + super(); + } + + setupMaterialComponents(componentHandler: any): boolean { + // workaround for MDL issues with dynamic components + if (componentHandler) { + componentHandler.upgradeAllRegistered(); + if (this.elementRef && this.hasValue()) { + let el = this.elementRef.nativeElement; + let container = el.querySelector('.mdl-textfield'); + if (container) { + container.MaterialTextfield.change(this.field.value); + } + } + + return true; + } + return false; + } + +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/index.ts b/ng2-components/ng2-activiti-form/src/components/widgets/index.ts index cc4dbeb362..ec4c30f78c 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/index.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/index.ts @@ -32,6 +32,7 @@ import { AttachWidget } from './attach/attach.widget'; import { TypeaheadWidget } from './typeahead/typeahead.widget'; import { FunctionalGroupWidget } from './functional-group/functional-group.widget'; import { PeopleWidget } from './people/people.widget'; +import { DateWidget } from './date/date.widget'; // core export * from './widget.component'; @@ -56,6 +57,7 @@ export * from './attach/attach.widget'; export * from './typeahead/typeahead.widget'; export * from './functional-group/functional-group.widget'; export * from './people/people.widget'; +export * from './date/date.widget'; export const WIDGET_DIRECTIVES: any[] = [ TabsWidget, @@ -73,5 +75,6 @@ export const WIDGET_DIRECTIVES: any[] = [ AttachWidget, TypeaheadWidget, FunctionalGroupWidget, - PeopleWidget + PeopleWidget, + DateWidget ];