From: Marcel Werk Date: Thu, 7 Nov 2024 14:51:23 +0000 (+0100) Subject: Add date range form field X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=6f873e442eadfac3d1a510492a790f3725d83b8f;p=GitHub%2FWoltLab%2FWCF.git Add date range form field --- diff --git a/com.woltlab.wcf/templates/shared_dateRangeFormField.tpl b/com.woltlab.wcf/templates/shared_dateRangeFormField.tpl new file mode 100644 index 0000000000..b0507cd43c --- /dev/null +++ b/com.woltlab.wcf/templates/shared_dateRangeFormField.tpl @@ -0,0 +1,23 @@ +getFieldClasses()|empty} class="{implode from=$field->getFieldClasses() item='class' glue=' '}{$class}{/implode}"{/if} + {if $field->isAutofocused()} autofocus{/if} + {if $field->isRequired()} required{/if} + {if $field->isImmutable()} disabled{/if} + {foreach from=$field->getFieldAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach} +> +getFieldClasses()|empty} class="{implode from=$field->getFieldClasses() item='class' glue=' '}{$class}{/implode}"{/if} + {if $field->isRequired()} required{/if} + {if $field->isImmutable()} disabled{/if} + {foreach from=$field->getFieldAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach} +> diff --git a/ts/WoltLabSuite/Core/Form/Builder/Field/DateRange.ts b/ts/WoltLabSuite/Core/Form/Builder/Field/DateRange.ts new file mode 100644 index 0000000000..3da01732f8 --- /dev/null +++ b/ts/WoltLabSuite/Core/Form/Builder/Field/DateRange.ts @@ -0,0 +1,43 @@ +/** + * Data handler for a date range form builder field in an Ajax form. + * + * @author Marcel Werk + * @copyright 2001-2024 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ +import Field from "./Field"; +import { FormBuilderData } from "../Data"; +import DatePicker from "../../../Date/Picker"; + +class DateRange extends Field { + #fromField: HTMLElement | null; + #toField: HTMLElement | null; + + constructor(fieldId: string) { + super(fieldId); + + this.#fromField = document.getElementById(this._fieldId + "_from"); + if (this.#fromField === null) { + throw new Error("Unknown field with id '" + this._fieldId + "'."); + } + + this.#toField = document.getElementById(this._fieldId + "_to"); + if (this.#toField === null) { + throw new Error("Unknown field with id '" + this._fieldId + "'."); + } + } + + protected _getData(): FormBuilderData { + return { + [this._fieldId]: { + from: DatePicker.getValue(this.#fromField as HTMLInputElement), + to: DatePicker.getValue(this.#toField as HTMLInputElement), + }, + }; + } + + protected _readField(): void {} +} + +export = DateRange; diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/DateRange.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/DateRange.js new file mode 100644 index 0000000000..b4d8d2d11d --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/DateRange.js @@ -0,0 +1,30 @@ +define(["require", "exports", "tslib", "./Field", "../../../Date/Picker"], function (require, exports, tslib_1, Field_1, Picker_1) { + "use strict"; + Field_1 = tslib_1.__importDefault(Field_1); + Picker_1 = tslib_1.__importDefault(Picker_1); + class DateRange extends Field_1.default { + #fromField; + #toField; + constructor(fieldId) { + super(fieldId); + this.#fromField = document.getElementById(this._fieldId + "_from"); + if (this.#fromField === null) { + throw new Error("Unknown field with id '" + this._fieldId + "'."); + } + this.#toField = document.getElementById(this._fieldId + "_to"); + if (this.#toField === null) { + throw new Error("Unknown field with id '" + this._fieldId + "'."); + } + } + _getData() { + return { + [this._fieldId]: { + from: Picker_1.default.getValue(this.#fromField), + to: Picker_1.default.getValue(this.#toField), + }, + }; + } + _readField() { } + } + return DateRange; +}); diff --git a/wcfsetup/install/files/lib/system/form/builder/field/DateRangeFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/DateRangeFormField.class.php new file mode 100644 index 0000000000..96d8a26666 --- /dev/null +++ b/wcfsetup/install/files/lib/system/form/builder/field/DateRangeFormField.class.php @@ -0,0 +1,161 @@ + + * @since 6.2 + */ +class DateRangeFormField extends AbstractFormField implements + IAttributeFormField, + IAutoFocusFormField, + ICssClassFormField, + IImmutableFormField, + INullableFormField +{ + use TAttributeFormField; + use TAutoFocusFormField; + use TCssClassFormField; + use TImmutableFormField; + use TNullableFormField; + + /** + * is `true` if not only the date, but also the time can be set + * @var bool + */ + protected $supportsTime = false; + + /** + * @inheritDoc + */ + protected $javaScriptDataHandlerModule = 'WoltLabSuite/Core/Form/Builder/Field/DateRange'; + + /** + * @inheritDoc + */ + protected $templateName = 'shared_dateRangeFormField'; + + const DATE_FORMAT = 'Y-m-d'; + + const TIME_FORMAT = 'Y-m-d\TH:i:sP'; + + /** + * @inheritDoc + */ + public function getSaveValue() + { + if ($this->getValue() === null && $this->isNullable()) { + return null; + } + + return $this->getFromValue() . ';' . $this->getToValue(); + } + + /** + * @inheritDoc + */ + public function readValue() + { + if ( + $this->getDocument()->hasRequestData($this->getPrefixedId()) + && \is_array($this->getDocument()->getRequestData($this->getPrefixedId())) + ) { + $this->value = $this->getDocument()->getRequestData($this->getPrefixedId()); + } + + return $this; + } + + /** + * Sets if not only the date, but also the time can be set. + */ + public function supportTime($supportsTime = true): static + { + if ($this->value !== null) { + throw new \BadFunctionCallException( + "After a value has been set, time support cannot be changed for field '{$this->getId()}'." + ); + } + + $this->supportsTime = $supportsTime; + + return $this; + } + + /** + * Returns `true` if not only the date, but also the time can be set, and + * returns `false` otherwise. + * + * By default, the time cannot be set. + */ + public function supportsTime(): bool + { + return $this->supportsTime; + } + + /** + * @inheritDoc + */ + public function validate() + { + if ($this->isRequired() && (!$this->getFromValue() || !$this->getToValue())) { + $this->addValidationError(new FormFieldValidationError('empty')); + } + + if ($this->getFromValue()) { + $dateTime = \DateTime::createFromFormat( + $this->supportsTime() ? self::TIME_FORMAT : self::DATE_FORMAT, + $this->getFromValue() + ); + if ($dateTime === false) { + $this->addValidationError(new FormFieldValidationError('invalid')); + } + } + + if ($this->getToValue()) { + $dateTime = \DateTime::createFromFormat( + $this->supportsTime() ? self::TIME_FORMAT : self::DATE_FORMAT, + $this->getToValue() + ); + if ($dateTime === false) { + $this->addValidationError(new FormFieldValidationError('invalid')); + } + } + } + + /** + * @inheritDoc + */ + public function value($value) + { + $values = \explode(';', $value); + if (\count($values) !== 2) { + throw new \InvalidArgumentException( + "Given value does not match format for field '{$this->getId()}'." + ); + } + + $this->value = [ + 'from' => $values[0], + 'to' => $values[1], + ]; + + return $this; + } + + public function getFromValue(): string + { + return $this->value['from'] ?? ''; + } + + public function getToValue(): string + { + return $this->value['to'] ?? ''; + } +}