--- /dev/null
+<button {*
+ *}type="submit" {*
+ *}id="{@$field->getPrefixedId()}" {*
+ *}name="{@$field->getPrefixedId()}" {*
+ *}value="{$field->getValue()}"{*
+*}>{$field->getButtonLabel()}</button>
--- /dev/null
+require(['WoltLabSuite/Core/Form/Builder/Field/Dependency/IsNotClicked'], function(IsNotClickedFieldDependency) {
+ // dependency '{@$dependency->getId()}'
+ new IsNotClickedFieldDependency(
+ '{@$dependency->getDependentNode()->getPrefixedId()}Container',
+ '{@$dependency->getField()->getPrefixedId()}'
+ );
+});
"templates": [
"__aclFormField",
"__booleanFormField",
+ "__buttonFormField",
"__contentLanguageFormField",
"__dateFormField",
"__emailFormField",
"__formFieldError",
"__formFieldErrors",
"__iconFormField",
+ "__isNotClickedFormFieldDependency",
"__itemListFormField",
"__labelFormField",
"__mediaSetCategoryDialog",
--- /dev/null
+<button {*
+ *}type="submit" {*
+ *}id="{@$field->getPrefixedId()}" {*
+ *}name="{@$field->getPrefixedId()}" {*
+ *}value="{$field->getValue()}"{*
+*}>{$field->getButtonLabel()}</button>
--- /dev/null
+require(['WoltLabSuite/Core/Form/Builder/Field/Dependency/IsNotClicked'], function(IsNotClickedFieldDependency) {
+ // dependency '{@$dependency->getId()}'
+ new IsNotClickedFieldDependency(
+ '{@$dependency->getDependentNode()->getPrefixedId()}Container',
+ '{@$dependency->getField()->getPrefixedId()}'
+ );
+});
cancelButton.addEventListener('click', this._closeDialog.bind(this));
elData(cancelButton, 'has-event-listener', 1);
}
+ this._additionalSubmitButtons = document.querySelectorAll(':not(.formSubmit) button[type="submit"]', dialogData.content);
+ this._additionalSubmitButtons.forEach((submit) => {
+ submit.addEventListener('click', (ev) => {
+ // Mark the button that was clicked so that the button data handlers know
+ // which data needs to be submitted.
+ this._additionalSubmitButtons.forEach((button) => {
+ button.dataset.isClicked = (button === submit) ? "1" : "0";
+ });
+ // Enable other `click` event listeners to be executed first before the form
+ // is submitted.
+ setTimeout(() => UiDialog.submit(this._dialogId), 0);
+ });
+ });
},
/**
* Submits the form with the given form data.
}
else if (typeof this._options.submitActionName === 'string') {
submitButton.disabled = true;
+ this._additionalSubmitButtons.forEach((submit) => submit.disabled = true);
Ajax.api(this, {
actionName: this._options.submitActionName,
parameters: {
--- /dev/null
+/**
+ * Data handler for a button form builder field in an Ajax form.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Form/Builder/Field/Value
+ * @since 5.4
+ */
+define(['Core', './Field'], function (Core, FormBuilderField) {
+ "use strict";
+ /**
+ * @constructor
+ */
+ function FormBuilderFieldButton(fieldId) {
+ this.init(fieldId);
+ }
+ ;
+ Core.inherit(FormBuilderFieldButton, FormBuilderField, {
+ /**
+ * @see WoltLabSuite/Core/Form/Builder/Field/Field#_getData
+ */
+ _getData: function () {
+ var data = {};
+ if (this._field.dataset.isClicked === "1") {
+ data[this._fieldId] = this._field.value;
+ }
+ return data;
+ }
+ });
+ return FormBuilderFieldButton;
+});
--- /dev/null
+/**
+ * Form field dependency implementation that requires that a button has not been clicked.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Form/Builder/Field/Dependency/IsNotClicked
+ * @see module:WoltLabSuite/Core/Form/Builder/Field/Dependency/Abstract
+ * @since 5.4
+ */
+define(['./Abstract', 'Core', './Manager'], function (Abstract, Core, DependencyManager) {
+ "use strict";
+ /**
+ * @constructor
+ */
+ function IsNotClicked(dependentElementId, fieldId) {
+ this.init(dependentElementId, fieldId);
+ this._field.addEventListener('click', () => {
+ this._field.dataset.isClicked = 1;
+ DependencyManager.checkDependencies();
+ });
+ }
+ ;
+ Core.inherit(IsNotClicked, Abstract, {
+ /**
+ * @see WoltLabSuite/Core/Form/Builder/Field/Dependency/Abstract#checkDependency
+ */
+ checkDependency: function () {
+ return this._field.dataset.isClicked !== "1";
+ }
+ });
+ return IsNotClicked;
+});
}
},
/**
- * Submits the dialog.
+ * Submits the dialog with the given id.
*/
_submit(id) {
const data = _dialogs.get(id);
}
}
},
+ /**
+ * Submits the dialog with the given id.
+ */
+ submit(id) {
+ this._submit(id);
+ },
/**
* Handles clicks on the close button or the backdrop if enabled.
*/
--- /dev/null
+<?php
+namespace wcf\system\form\builder\field;
+use wcf\system\form\builder\data\processor\CustomFormDataProcessor;
+use wcf\system\form\builder\IFormDocument;
+use wcf\system\WCF;
+
+/**
+ * Implementation of a form field for submit buttons.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Form\Builder\Field
+ * @since 5.4
+ */
+class ButtonFormField extends AbstractFormField {
+ /**
+ * text shown on the button
+ * @var ?string
+ */
+ protected $buttonLabel;
+
+ /**
+ * @inheritDoc
+ */
+ protected $javaScriptDataHandlerModule = 'WoltLabSuite/Core/Form/Builder/Field/Button';
+
+ /**
+ * @inheritDoc
+ */
+ protected $templateName = '__buttonFormField';
+
+ /**
+ * Sets the text shown on the button and returns this form field.
+ */
+ public function buttonLabel(string $languageItem, array $variables = []): self {
+ $this->buttonLabel = WCF::getLanguage()->getDynamicVariable($languageItem, $variables);
+
+ return $this;
+ }
+
+ /**
+ * Returns the text shown on the button.
+ */
+ public function getButtonLabel(): string {
+ if ($this->buttonLabel === null) {
+ throw new \BadMethodCallException("Button label has not been set.");
+ }
+
+ return $this->buttonLabel;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getHtml() {
+ if ($this->buttonLabel === null) {
+ throw new \UnexpectedValueException("Form field '{$this->getPrefixedId()}' requires a button label.");
+ }
+
+ return parent::getHtml();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function hasSaveValue() {
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function populate() {
+ parent::populate();
+
+ $this->getDocument()->getDataHandler()->addProcessor(new CustomFormDataProcessor('button', function(IFormDocument $document, array $parameters) {
+ if (!isset($parameters[$this->getObjectProperty()]) && $this->getValue() !== null) {
+ $parameters[$this->getObjectProperty()] = $this->getValue();
+ }
+
+ return $parameters;
+ }));
+
+ return $this;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function readValue() {
+ // The value of the button is set when setting up the form and has to be unset
+ // if the button was not clicked.
+ if (!$this->getDocument()->hasRequestData($this->getPrefixedId())) {
+ $this->value = null;
+ }
+
+ return $this;
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\form\builder\field\dependency;
+use wcf\system\exception\InvalidObjectArgument;
+use wcf\system\form\builder\field\ButtonFormField;
+use wcf\system\form\builder\field\IFormField;
+
+/**
+ * Represents a dependency that requires that a button has not been clicked.
+ *
+ * This dependency only works for `ButtonFormField` fields.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Form\Builder\Field\Dependency
+ * @since 5.4
+ */
+class IsNotClickedFormFieldDependency extends AbstractFormFieldDependency {
+ /**
+ * @inheritDoc
+ */
+ protected $templateName = '__isNotClickedFormFieldDependency';
+
+ /**
+ * @inheritDoc
+ */
+ public function checkDependency() {
+ $form = $this->getField()->getDocument();
+
+ // If no request data is given, the button was not clicked.
+ if (!$form->hasRequestData($this->getField()->getPrefixedId())) {
+ return true;
+ }
+
+ // Otherwise, the button is clicked if the relevant request data entry contains
+ // the button's value.
+ return $form->getRequestData($this->getField()->getPrefixedId()) !== $this->getField()->getValue();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function field(IFormField $field) {
+ if (!($field instanceof ButtonFormField)) {
+ throw new InvalidObjectArgument($field, ButtonFormField::class, 'Field');
+ }
+
+ return parent::field($field);
+ }
+}
cancelButton.addEventListener('click', this._closeDialog.bind(this));
elData(cancelButton, 'has-event-listener', 1);
}
+
+ this._additionalSubmitButtons = document.querySelectorAll(':not(.formSubmit) button[type="submit"]', dialogData.content);
+ this._additionalSubmitButtons.forEach((submit) => {
+ submit.addEventListener('click', (ev) => {
+ // Mark the button that was clicked so that the button data handlers know
+ // which data needs to be submitted.
+ this._additionalSubmitButtons.forEach((button) => {
+ button.dataset.isClicked = (button === submit) ? "1" : "0";
+ });
+
+ // Enable other `click` event listeners to be executed first before the form
+ // is submitted.
+ setTimeout(() => UiDialog.submit(this._dialogId), 0);
+ });
+ });
},
/**
}
else if (typeof this._options.submitActionName === 'string') {
submitButton.disabled = true;
+ this._additionalSubmitButtons.forEach((submit) => submit.disabled = true);
Ajax.api(this, {
actionName: this._options.submitActionName,
--- /dev/null
+/**
+ * Data handler for a button form builder field in an Ajax form.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Form/Builder/Field/Value
+ * @since 5.4
+ */
+define(['Core', './Field'], function(Core, FormBuilderField) {
+ "use strict";
+
+ /**
+ * @constructor
+ */
+ function FormBuilderFieldButton(fieldId) {
+ this.init(fieldId);
+ };
+ Core.inherit(FormBuilderFieldButton, FormBuilderField, {
+ /**
+ * @see WoltLabSuite/Core/Form/Builder/Field/Field#_getData
+ */
+ _getData: function() {
+ var data = {};
+
+ if (this._field.dataset.isClicked === "1") {
+ data[this._fieldId] = this._field.value;
+ }
+
+ return data;
+ }
+ });
+
+ return FormBuilderFieldButton;
+});
--- /dev/null
+/**
+ * Form field dependency implementation that requires that a button has not been clicked.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Form/Builder/Field/Dependency/IsNotClicked
+ * @see module:WoltLabSuite/Core/Form/Builder/Field/Dependency/Abstract
+ * @since 5.4
+ */
+define(['./Abstract', 'Core', './Manager'], function(Abstract, Core, DependencyManager) {
+ "use strict";
+
+ /**
+ * @constructor
+ */
+ function IsNotClicked(dependentElementId, fieldId) {
+ this.init(dependentElementId, fieldId);
+
+ this._field.addEventListener('click', () => {
+ this._field.dataset.isClicked = 1;
+
+ DependencyManager.checkDependencies();
+ });
+ };
+ Core.inherit(IsNotClicked, Abstract, {
+ /**
+ * @see WoltLabSuite/Core/Form/Builder/Field/Dependency/Abstract#checkDependency
+ */
+ checkDependency: function() {
+ return this._field.dataset.isClicked !== "1";
+ }
+ });
+
+ return IsNotClicked;
+});
},
/**
- * Submits the dialog.
+ * Submits the dialog with the given id.
*/
_submit(id: string): void {
const data = _dialogs.get(id);
}
},
+ /**
+ * Submits the dialog with the given id.
+ */
+ submit(id: string): void {
+ this._submit(id);
+ },
+
/**
* Handles clicks on the close button or the backdrop if enabled.
*/