Implement `BadgeColorFormField` to select a badge color or custom css class name
authorCyperghost <olaf_schmitz_1@t-online.de>
Mon, 18 Nov 2024 08:56:08 +0000 (09:56 +0100)
committerCyperghost <olaf_schmitz_1@t-online.de>
Mon, 18 Nov 2024 08:56:08 +0000 (09:56 +0100)
com.woltlab.wcf/templates/shared_badgeColorFormField.tpl [new file with mode: 0644]
ts/WoltLabSuite/Core/Form/Builder/Field/Controller/BadgeColor.ts [new file with mode: 0644]
wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Controller/BadgeColor.js [new file with mode: 0644]
wcfsetup/install/files/lib/system/form/builder/field/BadgeColorFormField.class.php [new file with mode: 0644]
wcfsetup/install/files/style/ui/label.scss

diff --git a/com.woltlab.wcf/templates/shared_badgeColorFormField.tpl b/com.woltlab.wcf/templates/shared_badgeColorFormField.tpl
new file mode 100644 (file)
index 0000000..006f92b
--- /dev/null
@@ -0,0 +1,43 @@
+<ul class="labelSelection">
+       {foreach from=$field->getOptions() item=color}
+               <li{if $color == 'custom'} class="custom"{/if}>
+                       <label class="labelSelection__label">
+                               <input {*
+                                       *}type="radio" {*
+                                       *}name="{$field->getPrefixedId()}" {*
+                                       *}value="{$color}"{*
+                                       *}{if !$field->getFieldClasses()|empty} class="{implode from=$field->getFieldClasses() item=class glue=' '}{$class}{/implode}"{/if}{*
+                                       *}{if $field->getValue() !== null && $field->getValue() == $color} checked{/if}{*
+                                       *}{if $field->isImmutable()} disabled{/if}{*
+                                       *}{foreach from=$field->getFieldAttributes() key=attributeName item=attributeValue} {$attributeName}="{$attributeValue}"{/foreach}{*
+                                       *}>
+                               {if $color == 'custom'}
+                                       <span class="labelSelection__span">
+                                               <input type="text" id="{$field->getPrefixedId()}Custom" name="{$field->getPrefixedId()}customCssClassName" value="{$field->getCustomClassName()}" class="long labelSelection__custom__input">
+                                       </span>
+                               {else}
+                                       <span class="labelSelection__span badge label{if $color != 'none'} {$color}{/if}">{$field->getDefaultLabelText()}</span>
+                               {/if}
+                       </label>
+               </li>
+       {/foreach}
+</ul>
+
+<script data-relocate="true">
+       {if $field->getTextReferenceNodeId()}
+               require(["WoltLabSuite/Core/Form/Builder/Field/Controller/BadgeColor"], ({ BadgeColorPreview }) => {
+                       new BadgeColorPreview(
+                               '{unsafe:$field->getPrefixedId()|encodeJS}Container',
+                               '{unsafe:$field->getTextReferenceNodeId()|encodeJS}',
+                               '{unsafe:$field->getDefaultLabelText()|encodeJS}',
+                       );
+               });
+       {/if}
+       const customInput = document.querySelector('#{unsafe:$field->getPrefixedId()|encodeJS}Container .labelSelection__custom__input');
+       const customRadioInput = document.querySelector('#{unsafe:$field->getPrefixedId()|encodeJS}Container .custom > .labelSelection__label > input[type="radio"]');
+       if (customInput && customRadioInput) {
+               customInput.addEventListener("focus", () => {
+                       customRadioInput.checked = true;
+               });
+       }
+</script>
diff --git a/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/BadgeColor.ts b/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/BadgeColor.ts
new file mode 100644 (file)
index 0000000..53ac857
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * @author    Olaf Braun
+ * @copyright 2001-2024 WoltLab GmbH
+ * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since     6.2
+ */
+
+export class BadgeColorPreview {
+  readonly #container: HTMLElement | null;
+  readonly #referenceField: HTMLInputElement | null;
+  readonly #defaultLabelText: string;
+
+  constructor(fieldId: string, referenceFieldId: string, defaultLabelText: string) {
+    this.#defaultLabelText = defaultLabelText;
+    this.#container = document.getElementById(fieldId);
+
+    if (this.#container === null) {
+      throw new Error("Unknown field with id '" + fieldId + "'.");
+    }
+    this.#referenceField = document.getElementById(referenceFieldId) as HTMLInputElement | null;
+    if (this.#referenceField === null) {
+      throw new Error("Unknown reference element '" + referenceFieldId + "'.");
+    }
+
+    this.#referenceField.addEventListener("input", () => this.#updatePreview());
+  }
+
+  #updatePreview(): void {
+    const value = this.#referenceField!.value.trim() || this.#defaultLabelText;
+    this.#container!.querySelectorAll(".labelSelection__span.badge").forEach((span: HTMLSpanElement) => {
+      span.textContent = value;
+    });
+  }
+}
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Controller/BadgeColor.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Controller/BadgeColor.js
new file mode 100644 (file)
index 0000000..3d9c535
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * @author    Olaf Braun
+ * @copyright 2001-2024 WoltLab GmbH
+ * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since     6.2
+ */
+define(["require", "exports"], function (require, exports) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.BadgeColorPreview = void 0;
+    class BadgeColorPreview {
+        #container;
+        #referenceField;
+        #defaultLabelText;
+        constructor(fieldId, referenceFieldId, defaultLabelText) {
+            this.#defaultLabelText = defaultLabelText;
+            this.#container = document.getElementById(fieldId);
+            if (this.#container === null) {
+                throw new Error("Unknown field with id '" + fieldId + "'.");
+            }
+            this.#referenceField = document.getElementById(referenceFieldId);
+            if (this.#referenceField === null) {
+                throw new Error("Unknown reference element '" + referenceFieldId + "'.");
+            }
+            this.#referenceField.addEventListener("input", () => this.#updatePreview());
+        }
+        #updatePreview() {
+            const value = this.#referenceField.value.trim() || this.#defaultLabelText;
+            this.#container.querySelectorAll(".labelSelection__span.badge").forEach((span) => {
+                span.textContent = value;
+            });
+        }
+    }
+    exports.BadgeColorPreview = BadgeColorPreview;
+});
diff --git a/wcfsetup/install/files/lib/system/form/builder/field/BadgeColorFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/BadgeColorFormField.class.php
new file mode 100644 (file)
index 0000000..e9607b0
--- /dev/null
@@ -0,0 +1,86 @@
+<?php
+
+namespace wcf\system\form\builder\field;
+
+use wcf\system\WCF;
+
+/**
+ * Implementation of a badge color form field for selecting a single color or a custom color.
+ *
+ * @author      Olaf Braun
+ * @copyright   2001-2024 WoltLab GmbH
+ * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ *
+ * @since       6.2
+ */
+final class BadgeColorFormField extends RadioButtonFormField implements IPatternFormField
+{
+    use TPatternFormField;
+
+    public const AVAILABLE_CSS_CLASSNAMES = [
+        'yellow',
+        'orange',
+        'brown',
+        'red',
+        'pink',
+        'purple',
+        'blue',
+        'green',
+        'black',
+
+        'none', /* not a real value */
+        'custom', /* not a real value */
+    ];
+    /**
+     * @inheritDoc
+     */
+    protected $templateName = 'shared_badgeColorFormField';
+    protected ?string $textReferenceNodeId;
+    protected string $defaultLabelText;
+    protected string $customClassName = '';
+
+    public function __construct()
+    {
+        $this
+            ->addFieldClass('labelSelection__radio')
+            ->defaultLabelText(WCF::getLanguage()->get('wcf.acp.label.defaultValue'))
+            ->options(\array_combine(self::AVAILABLE_CSS_CLASSNAMES, self::AVAILABLE_CSS_CLASSNAMES))
+            ->pattern('^-?[_a-zA-Z]+[_a-zA-Z0-9-]+$');
+    }
+
+    public function defaultLabelText(string $text): self
+    {
+        $this->defaultLabelText = $text;
+
+        return $this;
+    }
+
+    public function textReferenceNode(IFormField $field): self
+    {
+        $this->textReferenceNodeId = $field->getId();
+
+        return $this;
+    }
+
+    public function textReferenceNodeId(string $id): self
+    {
+        $this->textReferenceNodeId = $id;
+
+        return $this;
+    }
+
+    public function getDefaultLabelText(): string
+    {
+        return $this->defaultLabelText;
+    }
+
+    public function getTextReferenceNodeId(): ?string
+    {
+        return $this->textReferenceNodeId;
+    }
+
+    public function getCustomClassName(): string
+    {
+        return $this->customClassName;
+    }
+}
index 6ea245b1c23ec06607aa2b9f03f00f77a6be6b5f..373baa297077d30b84ec13c6ca771e0caf590344 100644 (file)
 .labelChooser > .dropdownToggle > span {
        cursor: pointer;
 }
+
+.labelSelection > li.custom {
+       display: flex;
+}
+
+.labelSelection__label {
+       display: flex;
+       flex: 1 1 auto;
+       align-items: center;
+       margin-bottom: 10px;
+}
+
+.labelSelection__radio {
+       flex: 0 0 auto;
+       margin-right: 7px;
+}
+
+.labelSelection > li.custom .labelSelection__span {
+       flex: 1 1 auto;
+}