diff --git a/client/src/app/site/config/components/config-field/config-field.component.scss b/client/src/app/site/config/components/config-field/config-field.component.scss
index b7475bb00..6980b01da 100644
--- a/client/src/app/site/config/components/config-field/config-field.component.scss
+++ b/client/src/app/site/config/components/config-field/config-field.component.scss
@@ -3,6 +3,35 @@
width: 100%;
}
+.datetimepicker-container {
+ margin-left: -20px;
+
+ .mat-form-field {
+ width: 50%;
+ box-sizing: border-box;
+ padding-left: 20px;
+
+ .suffix-wrapper {
+ display: flex;
+ align-items: center;
+
+ .mat-datepicker-toggle {
+ padding-left: 4px;
+ padding-right: 4px;
+
+ .mat-datepicker-toggle-default-icon {
+ width: 20px;
+ margin-bottom: 10px;
+ }
+ }
+
+ .ngx-material-timepicker-toggle {
+ width: 28px;
+ }
+ }
+ }
+}
+
/* limit the color bar of color inputs */
input[type='color'] {
max-width: 100px;
diff --git a/client/src/app/site/config/components/config-field/config-field.component.ts b/client/src/app/site/config/components/config-field/config-field.component.ts
index 1da619738..0696ee6e3 100644
--- a/client/src/app/site/config/components/config-field/config-field.component.ts
+++ b/client/src/app/site/config/components/config-field/config-field.component.ts
@@ -1,8 +1,10 @@
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
+import * as moment from 'moment';
+import { Moment } from 'moment';
import { distinctUntilChanged } from 'rxjs/operators';
import { BaseComponent } from 'app/base.component';
@@ -12,7 +14,7 @@ import { ViewConfig } from '../../models/view-config';
/**
* Component for a config field, used by the {@link ConfigListComponent}. Handles
- * all inpu types defined by the server, as well as updating the configs
+ * all input types defined by the server, as well as updating the configs
*
* @example
* ```ts
@@ -23,16 +25,12 @@ import { ViewConfig } from '../../models/view-config';
selector: 'os-config-field',
templateUrl: './config-field.component.html',
styleUrls: ['./config-field.component.scss'],
- changeDetection: ChangeDetectionStrategy.OnPush
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ encapsulation: ViewEncapsulation.None // to style the date and time pickers
})
export class ConfigFieldComponent extends BaseComponent implements OnInit {
public configItem: ViewConfig;
- /**
- * Date representation od the config value, used by the datetimepicker
- */
- public dateValue: Date;
-
/**
* Option to show a green check-icon.
*/
@@ -58,8 +56,6 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
*/
public translatedValue: object;
- public rawDate: Date;
-
/**
* The config item for this component. Just accepts components with already
* populated constants-info.
@@ -70,12 +66,18 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
this.configItem = value;
if (this.form) {
- this.form.patchValue(
- {
- value: this.configItem.value
- },
- { emitEvent: false }
- );
+ if (this.configItem.inputType === 'datetimepicker') {
+ // datetime has to be converted
+ const datetimeObj = this.unixToDateAndTime(this.configItem.value as number);
+ this.form.patchValue(datetimeObj, { emitEvent: false });
+ } else {
+ this.form.patchValue(
+ {
+ value: this.configItem.value
+ },
+ { emitEvent: false }
+ );
+ }
}
}
}
@@ -99,7 +101,6 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
* @param formBuilder FormBuilder
* @param cd ChangeDetectorRef
* @param repo ConfigRepositoryService
- * @param dateTimeAdapter DateTimeAdapter
*/
public constructor(
protected titleService: Title,
@@ -116,7 +117,9 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
*/
public ngOnInit(): void {
this.form = this.formBuilder.group({
- value: ['']
+ value: [''],
+ date: [''],
+ time: ['']
});
this.translatedValue = this.configItem.value;
if (
@@ -128,8 +131,9 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
this.translatedValue = this.translate.instant(this.configItem.value);
}
}
- if (this.configItem.inputType === 'datetimepicker') {
- this.dateValue = new Date(this.configItem.value as number);
+ if (this.configItem.inputType === 'datetimepicker' && this.configItem.value) {
+ const datetimeObj = this.unixToDateAndTime(this.configItem.value as number);
+ this.form.patchValue(datetimeObj);
}
this.form.patchValue({
value: this.translatedValue
@@ -143,6 +147,41 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
});
}
+ /**
+ * Helper function to split a unix timestamp into a date as a moment object and a time string in the form of HH:SS
+ *
+ * @param unix the timestamp
+ *
+ * @return an object with a date and a time field
+ */
+ private unixToDateAndTime(unix: number): { date: Moment; time: string } {
+ const date = moment.unix(unix);
+ const time = date.hours() + ':' + date.minutes();
+ return { date: date, time: time };
+ }
+
+ /**
+ * Helper function to fuse a moment object as the date part and a time string (HH:SS) as the time part.
+ *
+ * @param date the moment date object
+ * @param time the time string
+ *
+ * @return a unix timestamp
+ */
+ private dateAndTimeToUnix(date: Moment, time: string): number {
+ if (date) {
+ if (time) {
+ const timeSplit = time.split(':');
+ // + is faster than parseint and number(). ~~ would be fastest but prevented by linter...
+ date.hour(+timeSplit[0]);
+ date.minute(+timeSplit[1]);
+ }
+ return date.unix();
+ } else {
+ return null;
+ }
+ }
+
/**
* Trigger an update of the data
*/
@@ -152,7 +191,10 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
return;
}
if (this.configItem.inputType === 'datetimepicker') {
- this.dateValue = new Date(value as number);
+ // datetime has to be converted
+ const date = this.form.get('date').value;
+ const time = this.form.get('time').value;
+ value = this.dateAndTimeToUnix(date, time);
}
if (this.debounceTimeout !== null) {
clearTimeout(this.debounceTimeout);
@@ -214,6 +256,8 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
/**
* Sets the error on this field.
+ *
+ * @param error The error as string.
*/
private setError(error: string): void {
this.error = error;
@@ -226,6 +270,7 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
* input, textarea, choice or date
*
* @param type: the type of a config item
+ *
* @returns the template type
*/
public formType(type: string): string {
@@ -243,6 +288,7 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
* Checks of the config.type can be part of the form
*
* @param type the config.type of a setting
+ *
* @returns wheather it should be excluded or not
*/
public isExcludedType(type: string): boolean {
@@ -250,17 +296,6 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
return excluded.includes(type);
}
- /**
- * custom handler for datetime picker updates. Sets the form's value
- * to the timestamp of the Date being the event's value
- *
- * @param event an event-like object with a Date as value property
- */
- public updateTime(event: { value: Date }): void {
- this.dateValue = event.value;
- this.onChange(event.value.valueOf());
- }
-
/**
* Determines if a reset buton should be offered.
* TODO: is 'null' a valid default in some cases?
diff --git a/openslides/core/config_variables.py b/openslides/core/config_variables.py
index 74be5f693..d1cec9c2a 100644
--- a/openslides/core/config_variables.py
+++ b/openslides/core/config_variables.py
@@ -36,6 +36,7 @@ def get_config_variables():
yield ConfigVariable(
name="general_event_date",
default_value="",
+ input_type="datetimepicker",
label="Event date",
weight=120,
group="General",