From: Matthias Schmidt Date: Tue, 26 Mar 2019 17:17:16 +0000 (+0100) Subject: Add label form field X-Git-Tag: 5.2.0_Alpha_1~178^2 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=22c790fc12fcf831f18f28a1b191dcb71c1f872f;p=GitHub%2FWoltLab%2FWCF.git Add label form field See #2509 --- diff --git a/com.woltlab.wcf/templates/__labelFormField.tpl b/com.woltlab.wcf/templates/__labelFormField.tpl new file mode 100644 index 0000000000..071acec516 --- /dev/null +++ b/com.woltlab.wcf/templates/__labelFormField.tpl @@ -0,0 +1,46 @@ +{include file='__formFieldHeader'} + + + + + +{js application='wcf' file='WCF.Label' bundle='WCF.Combined'} + + +{include file='__formFieldFooter'} diff --git a/syncTemplates.json b/syncTemplates.json index e82e4f6871..f213ae4655 100644 --- a/syncTemplates.json +++ b/syncTemplates.json @@ -21,6 +21,7 @@ "__formFieldHeader", "__iconFormField", "__itemListFormField", + "__labelFormField", "__mediaSetCategoryDialog", "__multilineTextFormField", "__multiPageCondition", diff --git a/wcfsetup/install/files/acp/templates/__labelFormField.tpl b/wcfsetup/install/files/acp/templates/__labelFormField.tpl new file mode 100644 index 0000000000..071acec516 --- /dev/null +++ b/wcfsetup/install/files/acp/templates/__labelFormField.tpl @@ -0,0 +1,46 @@ +{include file='__formFieldHeader'} + + + + + +{js application='wcf' file='WCF.Label' bundle='WCF.Combined'} + + +{include file='__formFieldFooter'} diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Label.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Label.js new file mode 100644 index 0000000000..ef136f797e --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Label.js @@ -0,0 +1,152 @@ +/** + * Handles the JavaScript part of the label form field. + * + * @author Alexander Ebert, Matthias Schmidt + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Form/Builder/Field/Label + * @since 5.2 + */ +define(['Core', 'Dom/Util', 'Language', 'Ui/SimpleDropdown'], function(Core, DomUtil, Language, UiSimpleDropdown) { + "use strict"; + + /** + * @constructor + */ + function FormBuilderFieldLabel(fielId, labelId, options) { + this.init(fielId, labelId, options); + }; + FormBuilderFieldLabel.prototype = { + /** + * Initializes the label form field. + * + * @param {string} fieldId id of the relevant form builder field + * @param {integer} labelId id of the currently selected label + * @param {object} options additional label options + */ + init: function(fieldId, labelId, options) { + this._formFieldContainer = elById(fieldId + 'Container'); + this._labelChooser = elByClass('labelChooser', this._formFieldContainer)[0]; + this._options = Core.extend({ + forceSelection: false, + showWithoutSelection: false + }, options); + + this._input = elCreate('input'); + this._input.type = 'hidden'; + this._input.name = fieldId; + this._input.value = ~~labelId; + this._formFieldContainer.appendChild(this._input); + + var labelChooserId = DomUtil.identify(this._labelChooser); + + // init dropdown + var dropdownMenu = UiSimpleDropdown.getDropdownMenu(labelChooserId); + if (dropdownMenu === null) { + UiSimpleDropdown.init(elByClass('dropdownToggle', this._labelChooser)[0]); + dropdownMenu = UiSimpleDropdown.getDropdownMenu(labelChooserId); + } + + var additionalOptionList = null; + if (this._options.showWithoutSelection || !this._options.forceSelection) { + additionalOptionList = elCreate('ul'); + dropdownMenu.appendChild(additionalOptionList); + + var dropdownDivider = elCreate('li'); + dropdownDivider.className = 'dropdownDivider'; + additionalOptionList.appendChild(dropdownDivider); + } + + if (this._options.showWithoutSelection) { + var listItem = elCreate('li'); + elData(listItem, 'label-id', -1); + this._blockScroll(listItem); + additionalOptionList.appendChild(listItem); + + var span = elCreate('span'); + listItem.appendChild(span); + + var label = elCreate('span'); + label.className = 'badge label'; + label.innerHTML = Language.get('wcf.label.withoutSelection'); + span.appendChild(label); + } + + if (!this._options.forceSelection) { + var listItem = elCreate('li'); + elData(listItem, 'label-id', 0); + this._blockScroll(listItem); + additionalOptionList.appendChild(listItem); + + var span = elCreate('span'); + listItem.appendChild(span); + + var label = elCreate('span'); + label.className = 'badge label'; + label.innerHTML = Language.get('wcf.label.none'); + span.appendChild(label); + } + + elBySelAll('li:not(.dropdownDivider)', dropdownMenu, function(listItem) { + listItem.addEventListener('click', this._click.bind(this)); + + if (labelId) { + if (~~elData(listItem, 'label-id') === labelId) { + this._selectLabel(listItem); + } + } + }.bind(this)); + }, + + /** + * Blocks page scrolling for the given element. + * + * @param {HTMLElement} element + */ + _blockScroll: function(element) { + element.addEventListener( + 'wheel', + function(event) { + event.preventDefault(); + }, + { + passive: false + } + ); + }, + + /** + * Select a label after clicking on it. + * + * @param {Event} event click event in label selection dropdown + */ + _click: function(event) { + event.preventDefault(); + + this._selectLabel(event.currentTarget, false); + }, + + /** + * Selects the given label. + * + * @param {HTMLElement} label + */ + _selectLabel: function(label) { + // save label + var labelId = elData(label, 'label-id'); + if (!labelId) { + labelId = 0; + } + + // replace button with currently selected label + var displayLabel = elBySel('span > span', label); + var button = elBySel('.dropdownToggle > span', this._labelChooser); + button.className = displayLabel.className; + button.textContent = displayLabel.textContent; + + this._input.value = labelId; + } + }; + + return FormBuilderFieldLabel; +}); diff --git a/wcfsetup/install/files/lib/system/form/builder/field/label/LabelFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/label/LabelFormField.class.php new file mode 100644 index 0000000000..370715683e --- /dev/null +++ b/wcfsetup/install/files/lib/system/form/builder/field/label/LabelFormField.class.php @@ -0,0 +1,193 @@ + + * @package WoltLabSuite\Core\System\Form\Builder\Field + * @since 5.2 + */ +class LabelFormField extends AbstractFormField implements IObjectTypeFormNode { + use TObjectTypeFormNode; + + /** + * label group whose labels can be selected via this form field + * @var ViewableLabelGroup + */ + protected $labelGroup; + + /** + * @inheritDoc + */ + protected $templateName = '__labelFormField'; + + /** + * loaded labels grouped by label object type and object id to avoid loading the same labels + * over and over again for the same object and different label groups + * @var Label[][] + */ + protected static $loadedLabels = []; + + /** + * Returns the label group whose labels can be selected via this form field. + * + * @return ViewableLabelGroup label group whose labels can be selected + * @throws \BadMethodCallException if no label has been set + */ + public function getLabelGroup() { + if ($this->labelGroup === null) { + throw new \BadMethodCallException("No label group has been set."); + } + + return $this->labelGroup; + } + + /** + * @inheritDoc + */ + public function getObjectTypeDefinition() { + return 'com.woltlab.wcf.label.object'; + } + + /** + * @inheritDoc + */ + public function hasSaveValue() { + return false; + } + + /** + * Sets the label group whose labels can be selected via this form field and returns this + * form field. + * + * If no form field label has been set, the title of the label group will be set as label. + * + * @param ViewableLabelGroup $labelGroup label group whose labels can be selected + * @return static this form field + */ + public function labelGroup(ViewableLabelGroup $labelGroup) { + $this->labelGroup = $labelGroup; + + if ($this->label === null) { + $this->label($this->getLabelGroup()->getTitle()); + } + + return $this; + } + + /** + * @inheritDoc + */ + public function loadValueFromObject(IStorableObject $object) { + $objectTypeID = $this->getObjectType()->objectTypeID; + $objectID = $object->getObjectID(); + + if (!isset(static::$loadedLabels[$objectTypeID])) { + static::$loadedLabels[$objectTypeID] = []; + } + if (!isset(static::$loadedLabels[$objectTypeID][$objectID])) { + static::$loadedLabels[$objectTypeID][$objectID] = LabelHandler::getInstance()->getAssignedLabels( + $objectTypeID, + [$objectID] + )[$objectID]; + } + + $labelIDs = $this->getLabelGroup()->getLabelIDs(); + /** @var Label $label */ + foreach (static::$loadedLabels[$objectTypeID][$objectID] as $label) { + if (in_array($label->labelID, $labelIDs)) { + $this->value($label->labelID); + } + } + + return $this; + } + + /** + * @inheritDoc + */ + public function populate() { + parent::populate(); + + $this->getDocument()->getDataHandler()->add(new CustomFormFieldDataProcessor('label', function(IFormDocument $document, array $parameters) { + $value = $this->getValue(); + + // `-1` and `0` are special values that are irrlevent for saving + if ($value > 0) { + if (!isset($parameters[$this->getObjectProperty()])) { + $parameters[$this->getObjectProperty()] = []; + } + + $parameters[$this->getObjectProperty()][$this->getLabelGroup()->groupID] = $value; + } + + return $parameters; + })); + + return $this; + } + + /** + * @inheritDoc + */ + public function readValue() { + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $this->value = intval($this->getDocument()->getRequestData($this->getPrefixedId())); + } + + return $this; + } + + /** + * @inheritDoc + */ + public function validate() { + if ($this->isRequired()) { + if ($this->value <= 0) { + $this->addValidationError(new FormFieldValidationError('empty')); + } + } + else if ($this->value > 0 && !in_array($this->value, $this->getLabelGroup()->getLabelIDs())) { + $this->addValidationError(new FormFieldValidationError( + 'invalidValue', + 'wcf.global.form.error.noValidSelection' + )); + } + } + + /** + * Returns label group fields based for the given label groups using the given object property. + * + * The id of each form fields is `{$objectProperty}{$labelGroupID}`. + * + * @param string $objectType `com.woltlab.wcf.label.object` object type + * @param ViewableLabelGroup[] $labelGroups label groups for which label form fields are created + * @param string $objectProperty object property of form fields + * @return static[] + */ + public static function createFields($objectType, array $labelGroups, $objectProperty = 'labelIDs') { + $formFields = []; + foreach ($labelGroups as $labelGroup) { + $formFields[] = static::create($objectProperty . $labelGroup->groupID) + ->objectProperty($objectProperty) + ->objectType($objectType) + ->required($labelGroup->forceSelection) + ->labelGroup($labelGroup); + } + + return $formFields; + } +}