From e3d2c9a28ebc9210bff8842a0e75556f71cba834 Mon Sep 17 00:00:00 2001 From: Marcel Werk Date: Thu, 22 Oct 2026 12:28:22 +0200 Subject: [PATCH 1/3] Replace the label chooser with a new LabelPicker ref https://github.com/WoltLab/WCF/pull/5684 --- .../templates/__labelSelection.tpl | 32 +-- .../templates/shared_labelFormField.tpl | 40 +-- ts/WoltLabSuite/Core/Form/Builder/Data.ts | 3 + .../Form/Builder/Field/Controller/Label.ts | 1 + ts/WoltLabSuite/WebComponent/index.ts | 1 + .../WebComponent/woltlab-core-label-picker.ts | 230 ++++++++++++++++++ ts/global.d.ts | 12 + wcfsetup/install/files/js/WCF.Label.js | 1 + .../Form/Builder/Field/Controller/Label.js | 1 + .../files/js/WoltLabSuite/WebComponent.min.js | 37 ++- .../label/group/ViewableLabelGroup.class.php | 50 ++++ ...PreloadPhrasesCollectingListener.class.php | 3 + 12 files changed, 335 insertions(+), 76 deletions(-) create mode 100644 ts/WoltLabSuite/WebComponent/woltlab-core-label-picker.ts 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..9ac63e30738 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(), false, $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/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 `