Add SuffixFormFieldContainer
authorMatthias Schmidt <gravatronics@live.com>
Mon, 7 Oct 2019 16:12:07 +0000 (18:12 +0200)
committerMatthias Schmidt <gravatronics@live.com>
Mon, 7 Oct 2019 16:12:07 +0000 (18:12 +0200)
Close #3087

com.woltlab.wcf/templates/__suffixFormFieldContainer.tpl [new file with mode: 0644]
syncTemplates.json
wcfsetup/install/files/acp/templates/__suffixFormFieldContainer.tpl [new file with mode: 0644]
wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Container/SuffixFormField.js [new file with mode: 0644]
wcfsetup/install/files/lib/system/form/builder/container/SuffixFormFieldContainer.class.php [new file with mode: 0644]
wcfsetup/install/files/style/bootstrap/mixin/dropdownMenu.scss

diff --git a/com.woltlab.wcf/templates/__suffixFormFieldContainer.tpl b/com.woltlab.wcf/templates/__suffixFormFieldContainer.tpl
new file mode 100644 (file)
index 0000000..731d1c3
--- /dev/null
@@ -0,0 +1,57 @@
+<dl id="{@$element->getField()->getPrefixedId()}Container"{*
+       *}{if !$element->getField()->getClasses()|empty} class="{implode from=$element->getField()->getClasses() item='class' glue=' '}{$class}{/implode}"{/if}{*
+       *}{foreach from=$element->getField()->getAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}{*
+       *}{if !$element->getField()->checkDependencies()} style="display: none;"{/if}{*
+*}>
+       <dt>{if $element->getLabel() !== null}<label for="{@$element->getField()->getPrefixedId()}">{@$element->getLabel()}</label>{/if}</dt>
+       <dd>
+               <div class="inputAddon">
+                       {@$element->getField()->getFieldHtml()}
+                       
+                       {if $element->getSuffixField() !== null && $element->getSuffixField()->isAvailable()}
+                               {if !$element->suffixHasSelectableOptions()}
+                                       {if $element->getSuffixLabel() !== ''}
+                                               <span class="inputSuffix">{@$element->getSuffixLabel()}</span>
+                                       {/if}
+                               {else}
+                                       <span class="inputSuffix dropdown" id="{@$element->getSuffixField()->getPrefixedId()}_dropdown">
+                                               <span class="dropdownToggle">{@$element->getSelectedSuffixOption()[label]} <span class="icon icon16 fa-caret-down pointer"></span></span>
+                                               
+                                               <ul class="dropdownMenu">
+                                                       {foreach from=$element->getSuffixField()->getNestedOptions() item=__fieldNestedOption}
+                                                               <li{if ($element->getSuffixField()->getValue() == $__fieldNestedOption[value] && $__fieldNestedOption[isSelectable]) || !$__fieldNestedOption[isSelectable]} class="{if $element->getSuffixField()->getValue() == $__fieldNestedOption[value] && $__fieldNestedOption[isSelectable]}active{if !$__fieldNestedOption[isSelectable]} disabled{/if}{else}disabled{/if}"{/if} data-value="{$__fieldNestedOption[value]}" data-label="{$__fieldNestedOption[label]}"><span>{@'&nbsp;'|str_repeat:$__fieldNestedOption[depth] * 4}{@$__fieldNestedOption[label]}</span></li>
+                                                       {/foreach}
+                                               </ul>
+                                               <input type="hidden" id="{@$element->getSuffixField()->getPrefixedId()}" name="{@$element->getSuffixField()->getPrefixedId()}" value="{if $element->getSuffixField()->getValue() === null}{$element->getSelectedSuffixOption()[value]}{else}{$element->getSuffixField()->getValue()}{/if}" />
+                                       </span>
+                                       
+                                       {include file='__formFieldDependencies' field=$element->getSuffixField()}
+                                       {include file='__formFieldDataHandler' field=$element->getSuffixField()}
+                               {/if}
+                       {/if}
+               </div>
+               
+               {if $element->getDescription() !== null}
+                       <small>{@$element->getDescription()}</small>
+               {/if}
+               
+               {include file='__formFieldErrors' field=$element->getField()}
+               
+               {if $element->getSuffixField() !== null && $element->getSuffixField()->isAvailable()}
+                       {foreach from=$element->getSuffixField()->getValidationErrors() item='validationError'}
+                               {@$validationError->getHtml()}
+                       {/foreach}
+               {/if}
+               
+               {include file='__formFieldDependencies' field=$element->getField()}
+               {include file='__formFieldDataHandler' field=$element->getField()}
+       </dd>
+</dl>
+
+{if $element->getSuffixField() !== null && $element->getSuffixField()->isAvailable() && !$element->getSuffixField()->isImmutable() && $element->suffixHasSelectableOptions()}
+<script data-relocate="true">
+       require(['WoltLabSuite/Core/Form/Builder/Container/SuffixFormField'], function(FormBuilderSuffixFormFieldContainer) {
+               new FormBuilderSuffixFormFieldContainer('{@$element->getSuffixField()->getPrefixedId()}');
+       });
+</script>
+{/if}
index 24c8f421b21a7be9e948d6e9461a602f91656c78..11db7532e8ec3be259f6d10aac8353f94f83bac1 100644 (file)
@@ -36,6 +36,7 @@
     "__rowFormFieldContainer",
     "__singleMediaSelectionFormField",
     "__singleSelectionFormField",
+    "__suffixFormFieldContainer",
     "__tabFormContainer",
     "__tabMenuFormContainer",
     "__tabTabMenuFormContainer",
diff --git a/wcfsetup/install/files/acp/templates/__suffixFormFieldContainer.tpl b/wcfsetup/install/files/acp/templates/__suffixFormFieldContainer.tpl
new file mode 100644 (file)
index 0000000..c6ea9e6
--- /dev/null
@@ -0,0 +1,57 @@
+<dl id="{@$element->getField()->getPrefixedId()}Container"{*
+       *}{if !$element->getField()->getClasses()|empty} class="{implode from=$element->getField()->getClasses() item='class' glue=' '}{$class}{/implode}"{/if}{*
+       *}{foreach from=$element->getField()->getAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}{*
+       *}{if !$element->getField()->checkDependencies()} style="display: none;"{/if}{*
+*}>
+       <dt>{if $element->getLabel() !== null}<label for="{@$element->getField()->getPrefixedId()}">{@$element->getLabel()}</label>{/if}</dt>
+       <dd>
+               <div class="inputAddon">
+                       {@$element->getField()->getFieldHtml()}
+                       
+                       {if $element->getSuffixField() !== null && $element->getSuffixField()->isAvailable()}
+                               {if !$element->suffixHasSelectableOptions()}
+                                       {if $element->getSuffixLabel() !== ''}
+                                               <span class="inputSuffix">{@$element->getSuffixLabel()}</span>
+                                       {/if}
+                               {else}
+                                       <span class="inputSuffix dropdown" id="{@$element->getSuffixField()->getPrefixedId()}_dropdown">
+                                               <span class="dropdownToggle">{@$element->getSelectedSuffixOption()[label]} <span class="icon icon16 fa-caret-down pointer"></span></span>
+                                               
+                                               <ul class="dropdownMenu">
+                                                       {foreach from=$element->getSuffixField()->getNestedOptions() item=__fieldNestedOption}
+                                                               <li{if ($element->getSuffixField()->getValue() == $__fieldNestedOption[value] && $__fieldNestedOption[isSelectable]) || !$__fieldNestedOption[isSelectable]} class="{if $element->getSuffixField()->getValue() == $__fieldNestedOption[value] && $__fieldNestedOption[isSelectable]}active{if !$__fieldNestedOption[isSelectable]} disabled{/if}{else}disabled{/if}"{/if} data-value="{$__fieldNestedOption[value]}" data-label="{$__fieldNestedOption[label]}"><span>{@'&nbsp;'|str_repeat:$__fieldNestedOption[depth] * 4}{@$__fieldNestedOption[label]}</span></li>
+                                                       {/foreach}
+                                               </ul>
+                                               <input type="hidden" id="{@$element->getSuffixField()->getPrefixedId()}" name="{@$element->getSuffixField()->getPrefixedId()}" value="{if $element->getSuffixField()->getValue() === null}{$element->getSelectedSuffixOption()[value]}{else}{$element->getSuffixField()->getValue()}{/if}" />
+                                       </span>
+                                       
+                                       {include file='__formFieldDependencies' field=$element->getSuffixField()}
+                                       {include file='__formFieldDataHandler' field=$element->getSuffixField()}
+                               {/if}
+                       {/if}
+               </div>
+               
+               {if $element->getDescription() !== null}
+                       <small>{@$element->getDescription()}</small>
+               {/if}
+               
+               {include file='__formFieldErrors' field=$element->getField()}
+               
+               {if $element->getSuffixField() !== null && $element->getSuffixField()->isAvailable()}
+                       {foreach from=$element->getSuffixField()->getValidationErrors() item='validationError'}
+                               {@$validationError->getHtml()}
+                       {/foreach}
+               {/if}
+               
+               {include file='__formFieldDependencies' field=$element->getField()}
+               {include file='__formFieldDataHandler' field=$element->getField()}
+       </dd>
+</dl>
+
+{if $element->getSuffixField() !== null && $element->getSuffixField()->isAvailable() && !$element->getSuffixField()->isImmutable() && $element->suffixHasSelectableOptions()}
+<script data-relocate="true">
+       require(['WoltLabSuite/Core/Form/Builder/Container/SuffixFormField'], function(FormBuilderSuffixFormFieldContainer) {
+               new FormBuilderSuffixFormFieldContainer('{@$element->getDocument()->getId()}', '{@$element->getSuffixField()->getPrefixedId()}');
+       });
+</script>
+{/if}
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Container/SuffixFormField.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Container/SuffixFormField.js
new file mode 100644 (file)
index 0000000..f945113
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * Handles the dropdowns of form fields with a suffix.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module     WoltLabSuite/Core/Form/Builder/Container/SuffixFormField
+ * @since      5.2
+ */
+define(['EventHandler', 'Ui/SimpleDropdown'], function(EventHandler, UiSimpleDropdown) {
+       "use strict";
+       
+       /**
+        * @constructor
+        */
+       function PrefixSuffixFormFieldContainer(formId, suffixFieldId) {
+               this._formId = formId;
+               
+               this._suffixField = elById(suffixFieldId);
+               this._suffixDropdownMenu = UiSimpleDropdown.getDropdownMenu(suffixFieldId + '_dropdown');
+               this._suffixDropdownToggle = elByClass('dropdownToggle', UiSimpleDropdown.getDropdown(suffixFieldId + '_dropdown'))[0];
+               
+               var listItems = this._suffixDropdownMenu.children;
+               for (var i = 0, length = listItems.length; i < length; i++) {
+                       listItems[i].addEventListener('click', this._changeSuffixSelection.bind(this));
+               }
+               
+               EventHandler.add('WoltLabSuite/Core/Form/Builder/Manager', 'afterUnregisterForm', this._destroyDropdown.bind(this));
+       };
+       PrefixSuffixFormFieldContainer.prototype = {
+               /**
+                * Handles changing the suffix selection.
+                * 
+                * @param       {Event}         event
+                */
+               _changeSuffixSelection: function(event) {
+                       if (event.currentTarget.classList.contains('disabled')) {
+                               return;
+                       }
+                       
+                       var listItems = this._suffixDropdownMenu.children;
+                       for (var i = 0, length = listItems.length; i < length; i++) {
+                               if (listItems[i] === event.currentTarget) {
+                                       listItems[i].classList.add('active');
+                               }
+                               else {
+                                       listItems[i].classList.remove('active');
+                               }
+                       }
+                       
+                       this._suffixField.value = elData(event.currentTarget, 'value');
+                       this._suffixDropdownToggle.innerHTML = elData(event.currentTarget, 'label') + ' <span class="icon icon16 fa-caret-down pointer"></span>';
+               },
+               
+               /**
+                * Destorys the suffix dropdown if the parent form is unregistered.
+                * 
+                * @param       {object}        data    event data
+                */
+               _destroyDropdown: function(data) {
+                       if (data.formId === this._formId) {
+                               UiSimpleDropdown.destroy(this._suffixDropdownMenu.id);
+                       }
+               }
+       };
+       
+       return PrefixSuffixFormFieldContainer;
+});
diff --git a/wcfsetup/install/files/lib/system/form/builder/container/SuffixFormFieldContainer.class.php b/wcfsetup/install/files/lib/system/form/builder/container/SuffixFormFieldContainer.class.php
new file mode 100644 (file)
index 0000000..545aa3d
--- /dev/null
@@ -0,0 +1,171 @@
+<?php
+namespace wcf\system\form\builder\container;
+use wcf\system\form\builder\field\IFormField;
+use wcf\system\form\builder\field\IImmutableFormField;
+use wcf\system\form\builder\field\ISelectionFormField;
+use wcf\system\WCF;
+
+/**
+ * Represents a form field container for one main field with (optional) support for a suffix selection
+ * form field.
+ * 
+ * Child elements explicitly added to this container are not shown.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Form\Builder\Container
+ * @since      5.2
+ */
+class SuffixFormFieldContainer extends FormContainer {
+       /**
+        * form field to which the suffix selection is added
+        * @var IFormField
+        */
+       protected $field;
+       
+       /**
+        * selection form field containing the suffix options
+        * @var ISelectionFormField
+        */
+       protected $suffixField;
+       
+       /**
+        * Sets the form field to which the suffix selection is added and returns this field.
+        * 
+        * @param       IFormField      $formField
+        * @return      $this
+        */
+       public function field(IFormField $formField) {
+               if ($this->field !== null) {
+                       throw new \BadMethodCallException('Field has already been set.');
+               }
+               
+               $this->field = $formField;
+               $this->appendChild($formField);
+               
+               return $this;
+       }
+       
+       /**
+        * Returns the form field to which the suffix selection is added.
+        * 
+        * @return      IFormField
+        */
+       public function getField() {
+               if ($this->field === null) {
+                       throw new \BadMethodCallException('Field has not been set yet.');
+               }
+               
+               return $this->field;
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function getHtml() {
+               return WCF::getTPL()->fetch('__suffixFormFieldContainer', 'wcf', [
+                       'element' => $this
+               ]);
+       }
+       
+       /**
+        * Returns the intial option of the suffix selection dropdown.
+        * 
+        * @return      string
+        * @throws      \BadMethodCallException         if no suffix field is set or has no options
+        */
+       public function getSelectedSuffixOption() {
+               if ($this->getSuffixField() === null) {
+                       throw new \BadMethodCallException('There is no suffix field for which a label could be determined.');
+               }
+               if (empty($this->getSuffixField()->getOptions())) {
+                       throw new \BadMethodCallException('The suffix field has no options.');
+               }
+               
+               foreach ($this->getSuffixField()->getNestedOptions() as $option) {
+                       if ($this->getSuffixField()->getValue() === null) {
+                               if ($option['isSelectable']) {
+                                       return $option;
+                               }
+                       }
+                       else if ($option['value'] == $this->getSuffixField()->getValue()) {
+                               return $option;
+                       }
+               }
+               
+               throw new \RuntimeException('Cannot determine selected suffix option.');
+       }
+       
+       /**
+        * Returns the selection form field containing the suffix options.
+        * 
+        * @return      ISelectionFormField
+        */
+       public function getSuffixField() {
+               return $this->suffixField;
+       }
+       
+       /**
+        * Returns the label used for the suffix selection if the field has no selectable options
+        * or is immutable.
+        *
+        * @return      string
+        */
+       public function getSuffixLabel() {
+               if ($this->getSuffixField() === null) {
+                       throw new \BadMethodCallException('There is no suffix field for which a label could be determined.');
+               }
+               
+               if (empty($this->getSuffixField()->getOptions())) {
+                       return '';
+               }
+               
+               if (isset($this->getSuffixField()->getOptions()[$this->getSuffixField()->getValue()])) {
+                       return $this->getSuffixField()->getOptions()[$this->getSuffixField()->getValue()];
+               }
+               
+               return '';
+       }
+       
+       /**
+        * Sets the selection form field containing the suffix options.
+        *
+        * @param       ISelectionFormField     $formField
+        * @return      $this
+        * @throws      \BadMethodCallException         if no suffix field is set
+        */
+       public function suffixField(ISelectionFormField $formField) {
+               if ($this->suffixField !== null) {
+                       throw new \BadMethodCallException('Suffix field has already been set.');
+               }
+               
+               $this->suffixField = $formField;
+               $this->appendChild($formField);
+               
+               return $this;
+       }
+       
+       /**
+        * Returns `true` if the suffix selection has any selectable options.
+        * 
+        * @return      bool
+        */
+       public function suffixHasSelectableOptions() {
+               if ($this->getSuffixField() === null) {
+                       return false;
+               }
+               
+               if ($this->getSuffixField() instanceof IImmutableFormField && $this->getSuffixField()->isImmutable()) {
+                       return false;
+               }
+               
+               foreach ($this->getSuffixField()->getNestedOptions() as $option) {
+                       if ($option['isSelectable']) {
+                               return true;
+                       }
+               }
+               
+               return false;
+       }
+}
index 77cfc6ae7091603daf01edaf9888c9df9c1443d1..8b02bcbbc66f1333c28a200bc456c204148fbc7a 100644 (file)
                        }
                }
                
+               &.disabled {
+                       color: $wcfContentDimmedText;
+                       
+                       > span {
+                               cursor: not-allowed !important;
+                       }
+               }
+               
                > a,
                > span {
                        clear: both;