diff --git a/com.woltlab.wcf/templates/__labelSelection.tpl b/com.woltlab.wcf/templates/__labelSelection.tpl index cf11b517531..a953f5c97bb 100644 --- a/com.woltlab.wcf/templates/__labelSelection.tpl +++ b/com.woltlab.wcf/templates/__labelSelection.tpl @@ -1,31 +1,13 @@ {foreach from=$labelGroups item=labelGroup} {if $labelGroup|count} -
+ {assign var='__labelPickerID' value='labelGroup'|concat:$labelGroup->groupID} + {assign var='__labelPickerName' value='labelIDs['|concat:$labelGroup->groupID:']'} +
- - {if $noLabelSelectionNoScript|empty} - + {if $labelIDs[$labelGroup->groupID]|isset} + {unsafe:$labelGroup->renderPicker($__labelPickerName, $labelIDs[$labelGroup->groupID], false, true, $__labelPickerID)} + {else} + {unsafe:$labelGroup->renderPicker($__labelPickerName, 0, false, true, $__labelPickerID)} {/if}
{/if} diff --git a/com.woltlab.wcf/templates/shared_labelFormField.tpl b/com.woltlab.wcf/templates/shared_labelFormField.tpl index a3e95f2b374..0563b03755f 100644 --- a/com.woltlab.wcf/templates/shared_labelFormField.tpl +++ b/com.woltlab.wcf/templates/shared_labelFormField.tpl @@ -1,39 +1 @@ - - - - - +{unsafe:$field->getLabelGroup()->renderPicker($field->getPrefixedId(), $field->getValue(), $field->isRequired(), $field->isInvertible(), $field->getPrefixedId())} diff --git a/ts/WoltLabSuite/Core/Form/Builder/Data.ts b/ts/WoltLabSuite/Core/Form/Builder/Data.ts index f7b6990e2b3..11bb62dd795 100644 --- a/ts/WoltLabSuite/Core/Form/Builder/Data.ts +++ b/ts/WoltLabSuite/Core/Form/Builder/Data.ts @@ -24,6 +24,9 @@ export interface FormBuilderDialogOptions { usesDboAction: boolean; } +/** + * @deprecated 6.3 + */ export interface LabelFormFieldOptions { forceSelection: boolean; showWithoutSelection: boolean; diff --git a/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Label.ts b/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Label.ts index 6fd6646bcee..30ab549c174 100644 --- a/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Label.ts +++ b/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Label.ts @@ -5,6 +5,7 @@ * @copyright 2001-2020 WoltLab GmbH * @license GNU Lesser General Public License * @since 5.2 + * @deprecated 6.3 `LabelFormField` uses `` instead. */ import * as Core from "../../../../Core"; diff --git a/ts/WoltLabSuite/Core/Ui/Dropdown/Simple.ts b/ts/WoltLabSuite/Core/Ui/Dropdown/Simple.ts index f7a14e6d595..813a0766533 100644 --- a/ts/WoltLabSuite/Core/Ui/Dropdown/Simple.ts +++ b/ts/WoltLabSuite/Core/Ui/Dropdown/Simple.ts @@ -445,6 +445,14 @@ const UiDropdownSimple = { _menuContainer.appendChild(menu); const containerId = DomUtil.identify(dropdown); + + // A dropdown with the same id might have been removed from the DOM, + // e.g. when a dialog with a fixed set of ids is shown again. + const existingDropdown = _dropdowns.get(containerId); + if (existingDropdown !== undefined && existingDropdown !== dropdown && !existingDropdown.isConnected) { + UiDropdownSimple.destroy(containerId); + } + if (!_dropdowns.has(containerId)) { button.classList.add("jsDropdownEnabled"); button.addEventListener("click", toggle); diff --git a/ts/WoltLabSuite/WebComponent/index.ts b/ts/WoltLabSuite/WebComponent/index.ts index 3cf5a0c2c06..f41b104a1d7 100644 --- a/ts/WoltLabSuite/WebComponent/index.ts +++ b/ts/WoltLabSuite/WebComponent/index.ts @@ -13,6 +13,7 @@ import "./fa-brand.ts"; import "./fa-icon.ts"; import "./woltlab-core-date-time.ts"; import "./woltlab-core-file-upload.ts"; +import "./woltlab-core-label-picker.ts"; import "./woltlab-core-loading-indicator.ts"; import "./woltlab-core-notice.ts"; import "./woltlab-core-pagination.ts"; diff --git a/ts/WoltLabSuite/WebComponent/woltlab-core-label-picker.ts b/ts/WoltLabSuite/WebComponent/woltlab-core-label-picker.ts new file mode 100644 index 00000000000..86d6e1684f6 --- /dev/null +++ b/ts/WoltLabSuite/WebComponent/woltlab-core-label-picker.ts @@ -0,0 +1,230 @@ +/** + * `` provides a dropdown to select a single label + * out of a label group. The element is form-associated and submits the id of + * the selected label, `0` for no selection or `-1` for objects without any + * label of this group (requires `invertible`). + * + * Usage: `` + * + * @author Alexander Ebert, Marcel Werk + * @copyright 2001-2026 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.3 + */ + +{ + class WoltlabCoreLabelPickerElement extends HTMLElement { + static formAssociated = true; + + readonly #internals: ElementInternals; + #button: HTMLButtonElement | undefined = undefined; + #defaultValue = 0; + #items = new Map(); + #labels = new Map(); + + constructor() { + super(); + + this.#internals = this.attachInternals(); + } + + connectedCallback() { + // The dropdown menu is moved into a global container, building the + // element again when it is moved within the DOM would orphan it. + if (this.#button !== undefined) { + return; + } + + if (this.hasAttribute("labels")) { + this.#labels = new Map(JSON.parse(this.getAttribute("labels")!)); + this.removeAttribute("labels"); + } + + this.#defaultValue = this.value; + + this.innerHTML = ""; + this.classList.add("dropdown"); + + this.#button = document.createElement("button"); + this.#button.type = "button"; + this.#button.classList.add("dropdownToggle"); + this.#button.disabled = this.matches(":disabled"); + + this.append(this.#button, this.#buildMenu()); + + // Clicks on an associated `