From 4b683ecd9942030e2e31af4d6e46e9345cca05fa Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Mon, 28 May 2018 21:17:03 +0200 Subject: [PATCH] Add support for forms in dialogs See #2509 --- .../files/acp/templates/__dialogForm.tpl | 36 +++++++++ .../Form/Builder/Field/Dependency/Manager.js | 8 +- .../form/builder/DialogFormDocument.class.php | 68 +++++++++++++++++ .../form/builder/FormDocument.class.php | 74 ++++++++++++++++++- .../form/builder/IFormDocument.class.php | 33 +++++++++ .../field/AbstractNumericFormField.class.php | 16 ++-- .../builder/field/BooleanFormField.class.php | 4 +- .../builder/field/ItemListFormField.class.php | 8 +- .../field/SimpleAclFormField.class.php | 8 +- .../builder/field/TI18nFormField.class.php | 8 +- .../field/TSelectionFormField.class.php | 8 +- .../form/builder/field/TagFormField.class.php | 8 +- .../builder/field/UserFormField.class.php | 16 ++-- .../builder/field/UsernameFormField.class.php | 8 +- .../builder/field/WysiwygFormField.class.php | 8 +- 15 files changed, 277 insertions(+), 34 deletions(-) create mode 100644 wcfsetup/install/files/acp/templates/__dialogForm.tpl create mode 100644 wcfsetup/install/files/lib/system/form/builder/DialogFormDocument.class.php diff --git a/wcfsetup/install/files/acp/templates/__dialogForm.tpl b/wcfsetup/install/files/acp/templates/__dialogForm.tpl new file mode 100644 index 0000000000..a9e70ba54e --- /dev/null +++ b/wcfsetup/install/files/acp/templates/__dialogForm.tpl @@ -0,0 +1,36 @@ + + +{if $form->getAction()} + {capture assign='__formStart'}
getClasses()|empty} class="{implode from=$form->getClasses() item='class'}{$class}{/implode}"{/if}{foreach from=$form->getAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}> + {foreach from=$form item='child'} + {if $child->isAvailable()} + {@$child->getHtml()} + {/if} + {/foreach} + +
+ + {if $form->isCancelable()} + + {/if} +
+{@$__formEnd} + + diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Dependency/Manager.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Dependency/Manager.js index 4b92442c78..1b830d196c 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Dependency/Manager.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Dependency/Manager.js @@ -7,7 +7,7 @@ * @module WoltLabSuite/Core/Form/Builder/Field/Dependency/Manager * @since 3.2 */ -define(['Dictionary', 'Dom/ChangeListener', 'EventHandler', 'List', 'Dom/Util', 'ObjectMap'], function(Dictionary, DomChangeListener, EventHandler, List, DomUtil, ObjectMap) { +define(['Dictionary', 'Dom/ChangeListener', 'EventHandler', 'List', 'Dom/Traverse', 'Dom/Util', 'ObjectMap'], function(Dictionary, DomChangeListener, EventHandler, List, DomTraverse, DomUtil, ObjectMap) { "use strict"; /** @@ -276,7 +276,11 @@ define(['Dictionary', 'Dom/ChangeListener', 'EventHandler', 'List', 'Dom/Util', throw new Error("Unknown element with id '" + formId + "'"); } if (form.tagName !== 'FORM') { - throw new Error("Element with id '" + formId + "' is no form."); + var dialogContent = DomTraverse.parentByClass(form, 'dialogContent'); + + if (dialogContent === null) { + throw new Error("Element with id '" + formId + "' is no form."); + } } if (_forms.has(form)) { diff --git a/wcfsetup/install/files/lib/system/form/builder/DialogFormDocument.class.php b/wcfsetup/install/files/lib/system/form/builder/DialogFormDocument.class.php new file mode 100644 index 0000000000..c9fe55de21 --- /dev/null +++ b/wcfsetup/install/files/lib/system/form/builder/DialogFormDocument.class.php @@ -0,0 +1,68 @@ + + * @package WoltLabSuite\Core\System\Form\Builder + * @since 3.2 + */ +class DialogFormDocument extends FormDocument { + /** + * is `true` if dialog from can be canceled and is `false` otherwise + * @var bool + */ + protected $__isCancelable = true; + + /** + * Sets whether the dialog from can be canceled and return this document. + * + * @param bool $cancelable determines if dialog from can be canceled + * @return static this document + */ + public function cancelable(bool $cancelable = true): DialogFormDocument { + $this->__isCancelable = $cancelable; + + return $this; + } + + /** + * @inheritDoc + */ + public function getAction(): string { + // do not throw exception if no action has been set as a dialog + // form does not require an action to be set + if ($this->__action === null) { + $this->__action = ''; + } + + return $this->__action; + } + + /** + * @inheritDoc + */ + public function getHtml(): string { + return WCF::getTPL()->fetch( + '__dialogForm', + 'wcf', + array_merge($this->getHtmlVariables(), ['form' => $this]) + ); + } + + /** + * Returns `true` if the dialog from can be canceled and `false` otherwise. + * + * If it has not explicitly set whether the dialog form can be canceled, + * `true` is returned. + * + * @return bool + */ + public function isCancelable(): bool { + return $this->__isCancelable; + } +} diff --git a/wcfsetup/install/files/lib/system/form/builder/FormDocument.class.php b/wcfsetup/install/files/lib/system/form/builder/FormDocument.class.php index e362776b6a..8ce36c1578 100644 --- a/wcfsetup/install/files/lib/system/form/builder/FormDocument.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/FormDocument.class.php @@ -18,7 +18,9 @@ use wcf\system\WCF; */ class FormDocument implements IFormDocument { use TFormNode; - use TFormParentNode; + use TFormParentNode { + readValues as protected defaultReadValues; + } /** * `action` property of the HTML `form` element @@ -45,6 +47,12 @@ class FormDocument implements IFormDocument { */ protected $__prefix; + /** + * request data of the form's field + * @var null|array + */ + protected $__requestData; + /** * data handler for this document * @var IFormDataHandler @@ -193,9 +201,11 @@ class FormDocument implements IFormDocument { * @inheritDoc */ public function getHtml(): string { - return WCF::getTPL()->fetch('__form', 'wcf', array_merge($this->getHtmlVariables(), [ - 'form' => $this - ])); + return WCF::getTPL()->fetch( + '__form', + 'wcf', + array_merge($this->getHtmlVariables(), ['form' => $this]) + ); } /** @@ -216,6 +226,38 @@ class FormDocument implements IFormDocument { return $this->__prefix . '_'; } + /** + * @inheritDoc + */ + public function getRequestData(string $index = null) { + if ($this->__requestData === null) { + $this->__requestData = $_POST; + } + + if ($index !== null) { + if (!isset($this->__requestData[$index])) { + throw new \InvalidArgumentException("Unknown request data with index '" . $index . "'."); + } + + return $this->__requestData[$index]; + } + + return $this->__requestData; + } + + /** + * @inheritDoc + */ + public function hasRequestData(string $index = null): bool { + $requestData = $this->getRequestData(); + + if ($index !== null) { + return isset($requestData[$index]); + } + + return !empty($requestData); + } + /** * @inheritDoc */ @@ -269,4 +311,28 @@ class FormDocument implements IFormDocument { return $this; } + + /** + * @inheritDoc + */ + public function readValues(): IFormParentNode { + if ($this->__requestData === null) { + $this->__requestData = $_POST; + } + + return $this->defaultReadValues(); + } + + /** + * @inheritDoc + */ + public function requestData(array $requestData): IFormDocument { + if ($this->__requestData !== null) { + throw new \BadMethodCallException('Request data has already been set.'); + } + + $this->__requestData = $requestData; + + return $this; + } } diff --git a/wcfsetup/install/files/lib/system/form/builder/IFormDocument.class.php b/wcfsetup/install/files/lib/system/form/builder/IFormDocument.class.php index 4a694e12c8..261340787a 100644 --- a/wcfsetup/install/files/lib/system/form/builder/IFormDocument.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/IFormDocument.class.php @@ -126,6 +126,29 @@ interface IFormDocument extends IFormParentNode { */ public function getPrefix(): string; + /** + * Returns the request data of the form's fields. + * + * If no request data is set, `$_POST` will be set as the request data. + * + * @param null|string $index array index of the returned data + * @return array|mixed request data of the form's fields or specific index data if index is given + * + * @throws \InvalidArgumentException if invalid index is given + */ + public function getRequestData(string $index = null); + + /** + * Returns `true` if there is any request data or, if a parameter is given, if + * there is request data with a specific index. + * + * If no request data is set, `$_POST` will be set as the request data. + * + * @param null|string $index array index of the returned data + * @return bool `tu + */ + public function hasRequestData(string $index = null): bool; + /** * Loads the field values from the given object and returns this document. * @@ -160,4 +183,14 @@ interface IFormDocument extends IFormParentNode { * @throws \InvalidArgumentException if the given prefix is invalid */ public function prefix(string $prefix): IFormDocument; + + /** + * Sets the request data of the form's fields. + * + * @param array $requestData request data of the form's fields + * @return static this field + * + * @throws \BadMethodCallException if request data has already been set + */ + public function requestData(array $requestData): IFormDocument; } diff --git a/wcfsetup/install/files/lib/system/form/builder/field/AbstractNumericFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/AbstractNumericFormField.class.php index 1189e374e9..cb22f0dd7e 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/AbstractNumericFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/AbstractNumericFormField.class.php @@ -86,12 +86,16 @@ abstract class AbstractNumericFormField extends AbstractFormField implements IMa * @inheritDoc */ public function readValue(): IFormField { - if (isset($_POST[$this->getPrefixedId()]) && $_POST[$this->getPrefixedId()] !== '') { - if ($this->integerValues) { - $this->__value = intval($_POST[$this->getPrefixedId()]); - } - else { - $this->__value = floatval($_POST[$this->getPrefixedId()]); + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $value = $this->getDocument()->getRequestData($this->getPrefixedId()); + + if ($value !== '') { + if ($this->integerValues) { + $this->__value = intval($value); + } + else { + $this->__value = floatval($value); + } } } diff --git a/wcfsetup/install/files/lib/system/form/builder/field/BooleanFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/BooleanFormField.class.php index 5a6f769e0e..b90d609086 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/BooleanFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/BooleanFormField.class.php @@ -29,8 +29,8 @@ class BooleanFormField extends AbstractFormField { * @inheritDoc */ public function readValue(): IFormField { - if (isset($_POST[$this->getPrefixedId()])) { - $this->__value = $_POST[$this->getPrefixedId()] === '1'; + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $this->__value = $this->getDocument()->getRequestData($this->getPrefixedId()) === '1'; } return $this; diff --git a/wcfsetup/install/files/lib/system/form/builder/field/ItemListFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/ItemListFormField.class.php index 973ef1a713..6dac148468 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/ItemListFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/ItemListFormField.class.php @@ -114,8 +114,12 @@ class ItemListFormField extends AbstractFormField { * @inheritDoc */ public function readValue(): IFormField { - if (isset($_POST[$this->getPrefixedId()]) && is_array($_POST[$this->getPrefixedId()])) { - $this->__value = array_unique(ArrayUtil::trim($_POST[$this->getPrefixedId()])); + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $value = $this->getDocument()->getRequestData($this->getPrefixedId()); + + if (is_array($value)) { + $this->__value = array_unique(ArrayUtil::trim($value)); + } } return $this; diff --git a/wcfsetup/install/files/lib/system/form/builder/field/SimpleAclFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/SimpleAclFormField.class.php index 5f31ec654e..c3a2ae873a 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/SimpleAclFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/SimpleAclFormField.class.php @@ -63,8 +63,12 @@ class SimpleAclFormField extends AbstractFormField { * @inheritDoc */ public function readValue(): IFormField { - if (isset($_POST[$this->getPrefixedId()]) && is_array($_POST[$this->getPrefixedId()])) { - $this->__value = $_POST[$this->getPrefixedId()]; + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $value = $this->getDocument()->getRequestData($this->getPrefixedId()); + + if (is_array($value)) { + $this->__value = $value; + } } return $this; diff --git a/wcfsetup/install/files/lib/system/form/builder/field/TI18nFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/TI18nFormField.class.php index 58a5066d4a..44f0d65880 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/TI18nFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/TI18nFormField.class.php @@ -289,8 +289,12 @@ trait TI18nFormField { if ($this->isI18n()) { I18nHandler::getInstance()->readValues(); } - else if (isset($_POST[$this->getPrefixedId()]) && is_string($_POST[$this->getPrefixedId()])) { - $this->__value = StringUtil::trim($_POST[$this->getPrefixedId()]); + else if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $value = $this->getDocument()->getRequestData($this->getPrefixedId()); + + if (is_string($value)) { + $this->__value = StringUtil::trim($value); + } } return $this; diff --git a/wcfsetup/install/files/lib/system/form/builder/field/TSelectionFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/TSelectionFormField.class.php index 259184c746..46320758f2 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/TSelectionFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/TSelectionFormField.class.php @@ -137,8 +137,12 @@ trait TSelectionFormField { * @inheritDoc */ public function readValue(): IFormField { - if (isset($_POST[$this->getPrefixedId()]) && is_string($_POST[$this->getPrefixedId()])) { - $this->__value = $_POST[$this->getPrefixedId()]; + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $value = $this->getDocument()->getRequestData($this->getPrefixedId()); + + if (is_string($value)) { + $this->__value = $value; + } } return $this; diff --git a/wcfsetup/install/files/lib/system/form/builder/field/TagFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/TagFormField.class.php index 1626152d3b..79efe8dd21 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/TagFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/TagFormField.class.php @@ -101,8 +101,12 @@ class TagFormField extends AbstractFormField implements IObjectTypeFormField { * @inheritDoc */ public function readValue(): IFormField { - if (isset($_POST[$this->getPrefixedId()]) && is_array($_POST[$this->getPrefixedId()])) { - $this->__value = ArrayUtil::trim($_POST[$this->getPrefixedId()]); + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $value = $this->getDocument()->getRequestData($this->getPrefixedId()); + + if (is_array($value)) { + $this->__value = ArrayUtil::trim($value); + } } return $this; diff --git a/wcfsetup/install/files/lib/system/form/builder/field/UserFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/UserFormField.class.php index 3f8e50f33c..77da0c4a8c 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/UserFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/UserFormField.class.php @@ -27,12 +27,16 @@ class UserFormField extends AbstractFormField implements IMultipleFormField, INu * @inheritDoc */ public function readValue(): IFormField { - if (isset($_POST[$this->getPrefixedId()]) && is_string($_POST[$this->getPrefixedId()])) { - if ($this->allowsMultiple()) { - $this->__value = ArrayUtil::trim(explode(',', $_POST[$this->getPrefixedId()])); - } - else { - $this->__value = StringUtil::trim($_POST[$this->getPrefixedId()]); + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $value = $this->getDocument()->getRequestData($this->getPrefixedId()); + + if (is_string($value)) { + if ($this->allowsMultiple()) { + $this->__value = ArrayUtil::trim(explode(',', $value)); + } + else { + $this->__value = StringUtil::trim($value); + } } } diff --git a/wcfsetup/install/files/lib/system/form/builder/field/UsernameFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/UsernameFormField.class.php index 1d6cf08784..e20ce3dca0 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/UsernameFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/UsernameFormField.class.php @@ -48,8 +48,12 @@ class UsernameFormField extends AbstractFormField implements IMaximumLengthFormF * @inheritDoc */ public function readValue(): IFormField { - if (isset($_POST[$this->getPrefixedId()]) && is_string($_POST[$this->getPrefixedId()])) { - $this->__value = $_POST[$this->getPrefixedId()]; + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $value = $this->getDocument()->getRequestData($this->getPrefixedId()); + + if (is_string($value)) { + $this->__value = $value; + } } return $this; diff --git a/wcfsetup/install/files/lib/system/form/builder/field/WysiwygFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/WysiwygFormField.class.php index f38f6caeb8..d3c650591e 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/WysiwygFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/WysiwygFormField.class.php @@ -122,8 +122,12 @@ class WysiwygFormField extends AbstractFormField implements IMaximumLengthFormFi * @inheritDoc */ public function readValue(): IFormField { - if (isset($_POST[$this->getPrefixedId()])) { - $this->__value = StringUtil::trim($_POST[$this->getPrefixedId()]); + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $value = $this->getDocument()->getRequestData($this->getPrefixedId()); + + if (is_string($value)) { + $this->__value = StringUtil::trim($value); + } } return $this; -- 2.20.1