-<ul class="labelList jsOnly" data-object-id="{@$field->getLabelGroup()->groupID}">
- <li class="dropdown labelChooser" data-group-id="{@$field->getLabelGroup()->groupID}">
- <div class="dropdownToggle" data-toggle="labelGroup{@$field->getLabelGroup()->groupID}">
- <span class="badge label">{lang}wcf.label.none{/lang}</span>
- </div>
- <div class="dropdownMenu">
- <ul class="scrollableDropdownMenu">
- {foreach from=$field->getLabelGroup() item=label}
- <li data-label-id="{@$label->labelID}">
- <span>{@$label->render()}</span>
- </li>
- {/foreach}
- </ul>
- </div>
- </li>
-</ul>
-
-<noscript>
- <select name="{$field->getPrefixedId()}[{@$field->getLabelGroup()->groupID}]">
- {foreach from=$field->getLabelGroup() item=label}
- <option value="{$label->labelID}">{$label->getTitle()}</option>
- {/foreach}
- </select>
-</noscript>
-
-<script data-relocate="true">
- require(['Dom/Util', 'Language', 'WoltLabSuite/Core/Form/Builder/Field/Controller/Label'], function(DomUtil, Language, FormBuilderFieldLabel) {
- Language.addObject({
- 'wcf.label.none': '{jslang}wcf.label.none{/jslang}',
- 'wcf.label.withoutSelection': '{jslang}wcf.label.withoutSelection{/jslang}'
- });
-
- new FormBuilderFieldLabel(
- '{@$field->getPrefixedId()|encodeJS}',
- {if $field->getValue()}'{$field->getValue()|encodeJS}'{else}null{/if},
- {
- forceSelection: {if $field->getLabelGroup()->forceSelection}true{else}false{/if}
- }
- );
- });
-</script>
+{@$field->getLabelPicker()->toHtml()}
+++ /dev/null
-/**
- * Handles the JavaScript part of the label form field.
- *
- * @author Alexander Ebert, Matthias Schmidt
- * @copyright 2001-2020 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @since 5.2
- */
-
-import * as Core from "../../../../Core";
-import * as DomUtil from "../../../../Dom/Util";
-import * as Language from "../../../../Language";
-import UiDropdownSimple from "../../../../Ui/Dropdown/Simple";
-import { LabelFormFieldOptions } from "../../Data";
-
-class Label {
- protected readonly _formFieldContainer: HTMLElement;
- protected readonly _input: HTMLInputElement;
- protected readonly _labelChooser: HTMLElement;
- protected readonly _options: LabelFormFieldOptions;
-
- constructor(fieldId: string, labelId: string, options: Partial<LabelFormFieldOptions>) {
- this._formFieldContainer = document.getElementById(fieldId + "Container")!;
- this._labelChooser = this._formFieldContainer.getElementsByClassName("labelChooser")[0] as HTMLElement;
- this._options = Core.extend(
- {
- forceSelection: false,
- showWithoutSelection: false,
- },
- options,
- ) as LabelFormFieldOptions;
-
- this._input = document.createElement("input");
- this._input.type = "hidden";
- this._input.id = fieldId;
- this._input.name = fieldId;
- this._input.value = labelId;
- this._formFieldContainer.appendChild(this._input);
-
- const labelChooserId = DomUtil.identify(this._labelChooser);
-
- // init dropdown
- let dropdownMenu = UiDropdownSimple.getDropdownMenu(labelChooserId)!;
- if (dropdownMenu === null) {
- UiDropdownSimple.init(this._labelChooser.getElementsByClassName("dropdownToggle")[0] as HTMLElement);
- dropdownMenu = UiDropdownSimple.getDropdownMenu(labelChooserId)!;
- }
-
- let additionalOptionList: HTMLUListElement | null = null;
- if (this._options.showWithoutSelection || !this._options.forceSelection) {
- additionalOptionList = document.createElement("ul");
- dropdownMenu.appendChild(additionalOptionList);
-
- const dropdownDivider = document.createElement("li");
- dropdownDivider.classList.add("dropdownDivider");
- additionalOptionList.appendChild(dropdownDivider);
- }
-
- if (this._options.showWithoutSelection) {
- const listItem = document.createElement("li");
- listItem.dataset.labelId = "-1";
- this._blockScroll(listItem);
- additionalOptionList!.appendChild(listItem);
-
- const span = document.createElement("span");
- listItem.appendChild(span);
-
- const label = document.createElement("span");
- label.classList.add("badge", "label");
- label.innerHTML = Language.get("wcf.label.withoutSelection");
- span.appendChild(label);
- }
-
- if (!this._options.forceSelection) {
- const listItem = document.createElement("li");
- listItem.dataset.labelId = "0";
- this._blockScroll(listItem);
- additionalOptionList!.appendChild(listItem);
-
- const span = document.createElement("span");
- listItem.appendChild(span);
-
- const label = document.createElement("span");
- label.classList.add("badge", "label");
- label.innerHTML = Language.get("wcf.label.none");
- span.appendChild(label);
- }
-
- dropdownMenu.querySelectorAll("li:not(.dropdownDivider)").forEach((listItem: HTMLElement) => {
- listItem.addEventListener("click", (ev) => this._click(ev));
-
- if (labelId) {
- if (listItem.dataset.labelId === labelId) {
- this._selectLabel(listItem);
- }
- }
- });
- }
-
- _blockScroll(element: HTMLElement): void {
- element.addEventListener("wheel", (ev) => ev.preventDefault(), {
- passive: false,
- });
- }
-
- _click(event: Event): void {
- event.preventDefault();
-
- this._selectLabel(event.currentTarget as HTMLElement);
- }
-
- _selectLabel(label: HTMLElement): void {
- // save label
- let labelId = label.dataset.labelId;
- if (!labelId) {
- labelId = "0";
- }
-
- // replace button with currently selected label
- const displayLabel = label.querySelector("span > span")!;
- const button = this._labelChooser.querySelector(".dropdownToggle > span")!;
- button.className = displayLabel.className;
- button.textContent = displayLabel.textContent;
-
- this._input.value = labelId;
- }
-}
-
-export = Label;
-<ul class="labelList jsOnly" data-object-id="{@$field->getLabelGroup()->groupID}">
- <li class="dropdown labelChooser" data-group-id="{@$field->getLabelGroup()->groupID}">
- <div class="dropdownToggle" data-toggle="labelGroup{@$field->getLabelGroup()->groupID}">
- <span class="badge label">{lang}wcf.label.none{/lang}</span>
- </div>
- <div class="dropdownMenu">
- <ul class="scrollableDropdownMenu">
- {foreach from=$field->getLabelGroup() item=label}
- <li data-label-id="{@$label->labelID}">
- <span>{@$label->render()}</span>
- </li>
- {/foreach}
- </ul>
- </div>
- </li>
-</ul>
-
-<noscript>
- <select name="{$field->getPrefixedId()}[{@$field->getLabelGroup()->groupID}]">
- {foreach from=$field->getLabelGroup() item=label}
- <option value="{$label->labelID}">{$label->getTitle()}</option>
- {/foreach}
- </select>
-</noscript>
-
-<script data-relocate="true">
- require(['Dom/Util', 'Language', 'WoltLabSuite/Core/Form/Builder/Field/Controller/Label'], function(DomUtil, Language, FormBuilderFieldLabel) {
- Language.addObject({
- 'wcf.label.none': '{jslang}wcf.label.none{/jslang}',
- 'wcf.label.withoutSelection': '{jslang}wcf.label.withoutSelection{/jslang}'
- });
-
- new FormBuilderFieldLabel(
- '{@$field->getPrefixedId()|encodeJS}',
- {if $field->getValue()}'{$field->getValue()|encodeJS}'{else}null{/if},
- {
- forceSelection: {if $field->getLabelGroup()->forceSelection}true{else}false{/if}
- }
- );
- });
-</script>
+{@$field->getLabelPicker()->toHtml()}
+++ /dev/null
-/**
- * Handles the JavaScript part of the label form field.
- *
- * @author Alexander Ebert, Matthias Schmidt
- * @copyright 2001-2020 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @since 5.2
- */
-define(["require", "exports", "tslib", "../../../../Core", "../../../../Dom/Util", "../../../../Language", "../../../../Ui/Dropdown/Simple"], function (require, exports, tslib_1, Core, DomUtil, Language, Simple_1) {
- "use strict";
- Core = tslib_1.__importStar(Core);
- DomUtil = tslib_1.__importStar(DomUtil);
- Language = tslib_1.__importStar(Language);
- Simple_1 = tslib_1.__importDefault(Simple_1);
- class Label {
- _formFieldContainer;
- _input;
- _labelChooser;
- _options;
- constructor(fieldId, labelId, options) {
- this._formFieldContainer = document.getElementById(fieldId + "Container");
- this._labelChooser = this._formFieldContainer.getElementsByClassName("labelChooser")[0];
- this._options = Core.extend({
- forceSelection: false,
- showWithoutSelection: false,
- }, options);
- this._input = document.createElement("input");
- this._input.type = "hidden";
- this._input.id = fieldId;
- this._input.name = fieldId;
- this._input.value = labelId;
- this._formFieldContainer.appendChild(this._input);
- const labelChooserId = DomUtil.identify(this._labelChooser);
- // init dropdown
- let dropdownMenu = Simple_1.default.getDropdownMenu(labelChooserId);
- if (dropdownMenu === null) {
- Simple_1.default.init(this._labelChooser.getElementsByClassName("dropdownToggle")[0]);
- dropdownMenu = Simple_1.default.getDropdownMenu(labelChooserId);
- }
- let additionalOptionList = null;
- if (this._options.showWithoutSelection || !this._options.forceSelection) {
- additionalOptionList = document.createElement("ul");
- dropdownMenu.appendChild(additionalOptionList);
- const dropdownDivider = document.createElement("li");
- dropdownDivider.classList.add("dropdownDivider");
- additionalOptionList.appendChild(dropdownDivider);
- }
- if (this._options.showWithoutSelection) {
- const listItem = document.createElement("li");
- listItem.dataset.labelId = "-1";
- this._blockScroll(listItem);
- additionalOptionList.appendChild(listItem);
- const span = document.createElement("span");
- listItem.appendChild(span);
- const label = document.createElement("span");
- label.classList.add("badge", "label");
- label.innerHTML = Language.get("wcf.label.withoutSelection");
- span.appendChild(label);
- }
- if (!this._options.forceSelection) {
- const listItem = document.createElement("li");
- listItem.dataset.labelId = "0";
- this._blockScroll(listItem);
- additionalOptionList.appendChild(listItem);
- const span = document.createElement("span");
- listItem.appendChild(span);
- const label = document.createElement("span");
- label.classList.add("badge", "label");
- label.innerHTML = Language.get("wcf.label.none");
- span.appendChild(label);
- }
- dropdownMenu.querySelectorAll("li:not(.dropdownDivider)").forEach((listItem) => {
- listItem.addEventListener("click", (ev) => this._click(ev));
- if (labelId) {
- if (listItem.dataset.labelId === labelId) {
- this._selectLabel(listItem);
- }
- }
- });
- }
- _blockScroll(element) {
- element.addEventListener("wheel", (ev) => ev.preventDefault(), {
- passive: false,
- });
- }
- _click(event) {
- event.preventDefault();
- this._selectLabel(event.currentTarget);
- }
- _selectLabel(label) {
- // save label
- let labelId = label.dataset.labelId;
- if (!labelId) {
- labelId = "0";
- }
- // replace button with currently selected label
- const displayLabel = label.querySelector("span > span");
- const button = this._labelChooser.querySelector(".dropdownToggle > span");
- button.className = displayLabel.className;
- button.textContent = displayLabel.textContent;
- this._input.value = labelId;
- }
- }
- return Label;
-});
use wcf\system\form\builder\IObjectTypeFormNode;
use wcf\system\form\builder\TObjectTypeFormNode;
use wcf\system\label\LabelHandler;
+use wcf\system\label\LabelPicker;
+use wcf\system\label\LabelPickerGroup;
/**
* Implementation of a form field to select labels.
*/
protected $labelGroup;
+ protected LabelPickerGroup $labelPickerGroup;
+
/**
* @inheritDoc
*/
/**
* 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[][]
+ * @var Label[][][]
*/
protected static $loadedLabels = [];
/**
* Returns the label group whose labels can be selected via this form field.
+ */
+ public function getLabelGroup(): ViewableLabelGroup
+ {
+ return $this->getLabelPicker()->labelGroup;
+ }
+
+ /**
+ * Returns the label picker for this field.
*
- * @return ViewableLabelGroup label group whose labels can be selected
- * @throws \BadMethodCallException if no label has been set
+ * @since 6.1
*/
- public function getLabelGroup()
+ public function getLabelPicker(): LabelPicker
{
- if ($this->labelGroup === null) {
+ if (!isset($this->labelPickerGroup)) {
throw new \BadMethodCallException("No label group has been set for field '{$this->getId()}'.");
}
- return $this->labelGroup;
+ foreach ($this->labelPickerGroup as $labelPicker) {
+ return $labelPicker;
+ }
+
+ throw new \RuntimeException("Unreachable");
+ }
+
+ #[\Override]
+ public function getFieldHtml()
+ {
+ $this->labelPickerGroup->setName($this->getPrefixedId());
+ $this->getLabelPicker()->setElementID($this->getPrefixedId());
+
+ return parent::getFieldHtml();
}
/**
public function labelGroup(ViewableLabelGroup $labelGroup)
{
$this->labelGroup = $labelGroup;
+ $this->labelPickerGroup = LabelPickerGroup::fromViewableLabelGroups(
+ [$this->labelGroup],
+ false,
+ );
if ($this->label === null) {
$this->label($this->getLabelGroup()->getTitle());
static::$loadedLabels[$objectTypeID][$objectID] = $assignedLabels[$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);
- }
+ $this->labelPickerGroup->setSelectedLabelsFromAssignedLabels(self::$loadedLabels[$objectTypeID][$objectID]);
+ foreach ($this->labelPickerGroup as $labelPicker) {
+ $this->value($labelPicker->getSelectedValue());
+ break;
}
}
public function readValue()
{
if ($this->getDocument()->hasRequestData($this->getPrefixedId())) {
- $this->value = \intval($this->getDocument()->getRequestData($this->getPrefixedId()));
+ $this->labelPickerGroup->setSelectedLabels($this->getDocument()->getRequestData($this->getPrefixedId()));
+ $this->value = $this->getLabelPicker()->getSelectedValue();
}
return $this;