Add and use `LineBreakSeparatedTextUserGroupOptionType` (#4128)
authorMatthias Schmidt <gravatronics@live.com>
Sat, 17 Apr 2021 14:21:29 +0000 (16:21 +0200)
committerGitHub <noreply@github.com>
Sat, 17 Apr 2021 14:21:29 +0000 (16:21 +0200)
The internal implementation of `LineBreakSeparatedTextOptionType` and `Ui/ItemList/LineBreakSeparatedText` required minor adjustments for the list to have unique ids and for the input element to be part of the template so that the user group option type works on `UserGroupOptionForm`.

12 files changed:
com.woltlab.wcf/package.xml
com.woltlab.wcf/templates/lineBreakSeparatedTextOptionType.tpl [new file with mode: 0644]
com.woltlab.wcf/userGroupOption.xml
syncTemplates.json
ts/WoltLabSuite/Core/Ui/ItemList/LineBreakSeparatedText.ts
wcfsetup/install/files/acp/templates/lineBreakSeparatedTextOptionType.tpl
wcfsetup/install/files/acp/update_com.woltlab.wcf_5.4_deleteLanguageItems.php [new file with mode: 0644]
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/ItemList/LineBreakSeparatedText.js
wcfsetup/install/files/lib/system/option/LineBreakSeparatedTextOptionType.class.php
wcfsetup/install/files/lib/system/option/user/group/LineBreakSeparatedTextUserGroupOptionType.class.php [new file with mode: 0644]
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index 0e2f7542f14a0395a3a37a5d1f883324a5f7ea8e..77c69fa99410a4c628f64317b5568d075a099343 100644 (file)
@@ -130,5 +130,7 @@ tar cvf com.woltlab.wcf/files_pre.tar -C wcfsetup/install/files/ \
 
                <!-- Update of the Google Fonts -->
                <instruction type="script" run="standalone">acp/update_com.woltlab.wcf_5.4_update_google_font.php</instruction>
+               
+               <instruction type="script">acp/update_com.woltlab.wcf_5.4_deleteLanguageItems.php</instruction>
        </instructions>
 </package>
diff --git a/com.woltlab.wcf/templates/lineBreakSeparatedTextOptionType.tpl b/com.woltlab.wcf/templates/lineBreakSeparatedTextOptionType.tpl
new file mode 100644 (file)
index 0000000..55ef3f8
--- /dev/null
@@ -0,0 +1,26 @@
+<ul class="scrollableCheckboxList" {*
+    *}id="lineBreakSeparatedTextOption_{@$identifier}"{*
+    *}{if $values|empty} style="display: none"{/if}{*
+*}>
+    {foreach from=$values item=value}
+        <li data-value="{$value}">
+            <span class="icon icon16 fa-times jsDeleteItem jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}"></span>
+            <span>{$value}</span>
+        </li>
+    {/foreach}
+</ul>
+<input type="hidden" name="values[{$option->optionName}]">
+
+<script data-relocate="true">
+    require(['Language', 'WoltLabSuite/Core/Ui/ItemList/LineBreakSeparatedText'], (Language, { UiItemListLineBreakSeparatedText }) => {
+        Language.addObject({
+            'wcf.acp.option.type.lineBreakSeparatedText.placeholder': '{jslang}wcf.acp.option.type.lineBreakSeparatedText.placeholder{/jslang}',
+            'wcf.acp.option.type.lineBreakSeparatedText.error.duplicate': '{jslang __literal=true}wcf.acp.option.type.lineBreakSeparatedText.error.duplicate{/jslang}',
+            'wcf.acp.option.type.lineBreakSeparatedText.clearList.confirmMessage': '{jslang}wcf.acp.option.type.lineBreakSeparatedText.clearList.confirmMessage{/jslang}',
+        });
+        
+        new UiItemListLineBreakSeparatedText(
+            document.getElementById("lineBreakSeparatedTextOption_{@$identifier}")
+        );
+    });
+</script>
index eeb6a39bfeb44f49fbfbe62b02f87e21a428adcf..ee955acc692bcd6f32e3cf68a26656bcf2efd878 100644 (file)
                        </option>
                        <option name="user.attachment.allowedExtensions">
                                <categoryname>user.message.attachment</categoryname>
-                               <optiontype>textarea</optiontype>
+                               <optiontype>lineBreakSeparatedText</optiontype>
                                <defaultvalue>gif
 jpg
 jpeg
@@ -620,7 +620,7 @@ pdf</defaultvalue>
                        </option>
                        <option name="user.contactForm.attachment.allowedExtensions">
                                <categoryname>user.message.contactForm</categoryname>
-                               <optiontype>textarea</optiontype>
+                               <optiontype>lineBreakSeparatedText</optiontype>
                                <defaultvalue>gif
 jpg
 jpeg
@@ -682,7 +682,7 @@ pdf</defaultvalue>
                        </option>
                        <option name="user.signature.attachment.allowedExtensions">
                                <categoryname>user.signature</categoryname>
-                               <optiontype>textarea</optiontype>
+                               <optiontype>lineBreakSeparatedText</optiontype>
                                <defaultvalue>gif
 jpg
 jpeg
@@ -810,7 +810,7 @@ bmp</defaultvalue>
                        </option>
                        <option name="user.profile.avatar.allowedFileExtensions">
                                <categoryname>user.profile.avatar</categoryname>
-                               <optiontype>textarea</optiontype>
+                               <optiontype>lineBreakSeparatedText</optiontype>
                                <defaultvalue>gif
 jpg
 jpeg
index 4de5d1deec21eda36bc619c09cd58b4d8c779eee..620a176f0cf84e0f4e82d58fe66a83ab7a207927 100644 (file)
@@ -75,6 +75,7 @@
     "formNotice",
     "formSuccess",
     "languageChooser",
+    "lineBreakSeparatedTextOptionType",
     "mediaBBCodeTag",
     "mediaManager",
     "multipleLanguageInputJavascript",
index 3fde6f417d4b318e19b36d6dd7dab1d06c544a33..1f00d74fbcd79601d8b1bb856650f0f640f6ef36 100644 (file)
@@ -14,7 +14,7 @@ import * as Language from "../../Language";
 import DomUtil from "../../Dom/Util";
 
 export interface LineBreakSeparatedTextOptions {
-  submitFieldName: string;
+  submitFieldName?: string;
 }
 
 export class UiItemListLineBreakSeparatedText {
@@ -23,11 +23,21 @@ export class UiItemListLineBreakSeparatedText {
   protected readonly itemList: HTMLUListElement;
   protected readonly items = new Set<string>();
   protected readonly options: LineBreakSeparatedTextOptions;
+  protected readonly submitField?: HTMLInputElement = undefined;
 
-  constructor(itemList: HTMLUListElement, options: LineBreakSeparatedTextOptions) {
+  constructor(itemList: HTMLUListElement, options: LineBreakSeparatedTextOptions = {}) {
     this.itemList = itemList;
     this.options = options;
 
+    if (!this.options.submitFieldName) {
+      const nextElement = this.itemList.nextElementSibling;
+      if (nextElement instanceof HTMLInputElement && nextElement.type === "hidden") {
+        this.submitField = nextElement;
+      } else {
+        throw new Error("Missing `submitFieldName` option");
+      }
+    }
+
     this.itemList.closest("form")!.addEventListener("submit", () => this.submit());
 
     this.initValues();
@@ -241,11 +251,17 @@ export class UiItemListLineBreakSeparatedText {
    * Adds a hidden input field with the data to the form before it is submitted.
    */
   protected submit(): void {
-    const input = document.createElement("input");
-    input.type = "hidden";
-    input.name = this.options.submitFieldName;
-    input.value = Array.from(this.items).join("\n");
-    this.itemList.parentElement!.append(input);
+    const value = Array.from(this.items).join("\n");
+
+    if (this.submitField) {
+      this.submitField.value = value;
+    } else {
+      const input = document.createElement("input");
+      input.type = "hidden";
+      input.name = this.options.submitFieldName!;
+      input.value = value;
+      this.itemList.parentElement!.append(input);
+    }
   }
 }
 
index bc5a5bc08434a931d9d92733e0eb39e887950246..55ef3f857d6a1b0c292a00414e43facb8fa6c254 100644 (file)
@@ -1,5 +1,5 @@
 <ul class="scrollableCheckboxList" {*
-    *}id="lineBreakSeparatedTextOption_{@$option->optionID}"{*
+    *}id="lineBreakSeparatedTextOption_{@$identifier}"{*
     *}{if $values|empty} style="display: none"{/if}{*
 *}>
     {foreach from=$values item=value}
@@ -9,6 +9,7 @@
         </li>
     {/foreach}
 </ul>
+<input type="hidden" name="values[{$option->optionName}]">
 
 <script data-relocate="true">
     require(['Language', 'WoltLabSuite/Core/Ui/ItemList/LineBreakSeparatedText'], (Language, { UiItemListLineBreakSeparatedText }) => {
         });
         
         new UiItemListLineBreakSeparatedText(
-            document.getElementById("lineBreakSeparatedTextOption_{@$option->optionID}"),
-            {
-                submitFieldName: "values[{$option->optionName}]"
-            }
+            document.getElementById("lineBreakSeparatedTextOption_{@$identifier}")
         );
     });
 </script>
diff --git a/wcfsetup/install/files/acp/update_com.woltlab.wcf_5.4_deleteLanguageItems.php b/wcfsetup/install/files/acp/update_com.woltlab.wcf_5.4_deleteLanguageItems.php
new file mode 100644 (file)
index 0000000..dc35b80
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+use wcf\data\language\item\LanguageItemAction;
+use wcf\data\language\item\LanguageItemList;
+
+$languageItems = [
+    'wcf.acp.group.option.user.attachment.allowedExtensions.description',
+    'wcf.acp.group.option.user.contactForm.attachment.allowedExtensions.description',
+    'wcf.acp.group.option.user.signature.attachment.allowedExtensions.description',
+];
+
+$languageItemList = new LanguageItemList();
+$languageItemList->getConditionBuilder()->add('languageItem IN (?)', [$languageItems]);
+$languageItemList->readObjects();
+
+(new LanguageItemAction([$languageItemList->getObjects()], 'delete'))->executeAction();
index 3c1f02b7a32014d97ff84d0a82071a430acf083d..b8ef7ca4549f585c235373ccf56a0e0c76e08273 100644 (file)
@@ -16,12 +16,22 @@ define(["require", "exports", "tslib", "../Confirmation", "../../Language", "../
     Language = tslib_1.__importStar(Language);
     Util_1 = tslib_1.__importDefault(Util_1);
     class UiItemListLineBreakSeparatedText {
-        constructor(itemList, options) {
+        constructor(itemList, options = {}) {
             this.clearButton = undefined;
             this.itemInput = undefined;
             this.items = new Set();
+            this.submitField = undefined;
             this.itemList = itemList;
             this.options = options;
+            if (!this.options.submitFieldName) {
+                const nextElement = this.itemList.nextElementSibling;
+                if (nextElement instanceof HTMLInputElement && nextElement.type === "hidden") {
+                    this.submitField = nextElement;
+                }
+                else {
+                    throw new Error("Missing `submitFieldName` option");
+                }
+            }
             this.itemList.closest("form").addEventListener("submit", () => this.submit());
             this.initValues();
             this.buildUi();
@@ -197,11 +207,17 @@ define(["require", "exports", "tslib", "../Confirmation", "../../Language", "../
          * Adds a hidden input field with the data to the form before it is submitted.
          */
         submit() {
-            const input = document.createElement("input");
-            input.type = "hidden";
-            input.name = this.options.submitFieldName;
-            input.value = Array.from(this.items).join("\n");
-            this.itemList.parentElement.append(input);
+            const value = Array.from(this.items).join("\n");
+            if (this.submitField) {
+                this.submitField.value = value;
+            }
+            else {
+                const input = document.createElement("input");
+                input.type = "hidden";
+                input.name = this.options.submitFieldName;
+                input.value = value;
+                this.itemList.parentElement.append(input);
+            }
         }
     }
     exports.UiItemListLineBreakSeparatedText = UiItemListLineBreakSeparatedText;
index c21263cbdf99fc7097be4ccb5ba14b904336637d..2144c49ae4c18ecad5cd7cf389809d99485b2f5b 100644 (file)
@@ -26,7 +26,14 @@ class LineBreakSeparatedTextOptionType extends TextareaOptionType
         $values = ArrayUtil::trim(\explode("\n", StringUtil::unifyNewlines($value)));
         \uasort($values, 'strnatcmp');
 
+        static $identifiers = [];
+        do {
+            $identifier = \substr(StringUtil::getRandomID(), 0, 8);
+        } while (\in_array($identifier, $identifiers));
+        $identifiers[] = $identifier;
+
         return WCF::getTPL()->fetch('lineBreakSeparatedTextOptionType', 'wcf', [
+            'identifier' => $identifier,
             'option' => $option,
             'values' => $values,
         ]);
diff --git a/wcfsetup/install/files/lib/system/option/user/group/LineBreakSeparatedTextUserGroupOptionType.class.php b/wcfsetup/install/files/lib/system/option/user/group/LineBreakSeparatedTextUserGroupOptionType.class.php
new file mode 100644 (file)
index 0000000..89846a8
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+namespace wcf\system\option\user\group;
+
+use wcf\system\option\LineBreakSeparatedTextOptionType;
+use wcf\util\StringUtil;
+
+/**
+ * User group option type implementation for separate items that are stored as line break-separated
+ * text.
+ *
+ * The merge of option values returns merge of all text values.
+ *
+ * @author  Matthias Schmidt
+ * @copyright   2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Option\User\Group
+ * @since   5.4
+ */
+class LineBreakSeparatedTextUserGroupOptionType extends LineBreakSeparatedTextOptionType implements IUserGroupOptionType
+{
+    /**
+     * @inheritDoc
+     */
+    public function merge($defaultValue, $groupValue)
+    {
+        $defaultValue = empty($defaultValue) ? [] : \explode("\n", StringUtil::unifyNewlines($defaultValue));
+        $groupValue = empty($groupValue) ? [] : \explode("\n", StringUtil::unifyNewlines($groupValue));
+
+        return \implode("\n", \array_unique(\array_merge($defaultValue, $groupValue)));
+    }
+}
index 7f00bf51981dcc65e3292dee4480051580f653a2..61114990b920469a04bd5817a4dac27d76779c28 100644 (file)
@@ -743,7 +743,6 @@ ACHTUNG: Die oben genannten Meldungen sind stark gekürzt. Sie können Details z
                <item name="wcf.acp.group.option.category.user.message.attachment"><![CDATA[Dateianhänge]]></item>
                <item name="wcf.acp.group.option.user.attachment.maxSize"><![CDATA[Maximale Dateianhangsgröße]]></item>
                <item name="wcf.acp.group.option.user.attachment.allowedExtensions"><![CDATA[Erlaubte Dateiendungen]]></item>
-               <item name="wcf.acp.group.option.user.attachment.allowedExtensions.description"><![CDATA[Eine Dateiendung pro Zeile]]></item>
                <item name="wcf.acp.group.option.user.attachment.maxCount"><![CDATA[Maximale Dateianhänge pro Nachricht]]></item>
                <item name="wcf.acp.group.option.user.attachment.maxCount.description"/>
                <item name="wcf.acp.group.option.category.admin.attachment"><![CDATA[Dateianhänge]]></item>
@@ -896,7 +895,6 @@ ACHTUNG: Die oben genannten Meldungen sind stark gekürzt. Sie können Details z
                <item name="wcf.acp.group.option.category.user.message.contactForm"><![CDATA[Kontaktformular]]></item>
                <item name="wcf.acp.group.option.user.contactForm.attachment.maxSize"><![CDATA[Maximale Dateianhangsgröße]]></item>
                <item name="wcf.acp.group.option.user.contactForm.attachment.allowedExtensions"><![CDATA[Erlaubte Dateiendungen]]></item>
-               <item name="wcf.acp.group.option.user.contactForm.attachment.allowedExtensions.description"><![CDATA[Eine Dateiendung pro Zeile]]></item>
                <item name="wcf.acp.group.option.user.contactForm.attachment.maxCount"><![CDATA[Maximale Dateianhänge pro Nachricht]]></item>
                <item name="wcf.acp.group.option.user.profile.canEditUserProfile"><![CDATA[Kann eigenes Profil bearbeiten]]></item>
                <item name="wcf.acp.group.option.user.profile.canHideOnlineStatus"><![CDATA[Kann Online-Status verbergen]]></item>
@@ -907,7 +905,6 @@ ACHTUNG: Die oben genannten Meldungen sind stark gekürzt. Sie können Details z
                <item name="wcf.acp.group.option.user.signature.attachment.canUpload"><![CDATA[Kann Dateianhänge hochladen]]></item>
                <item name="wcf.acp.group.option.user.signature.attachment.maxSize"><![CDATA[Maximale Dateianhangsgröße]]></item>
                <item name="wcf.acp.group.option.user.signature.attachment.allowedExtensions"><![CDATA[Erlaubte Dateiendungen]]></item>
-               <item name="wcf.acp.group.option.user.signature.attachment.allowedExtensions.description"><![CDATA[Eine Dateiendung pro Zeile]]></item>
                <item name="wcf.acp.group.option.user.signature.attachment.maxCount"><![CDATA[Maximale Dateianhänge]]></item>
                <item name="wcf.acp.group.requireMultifactor"><![CDATA[Mehrfaktor-Authentifizierung erzwingen]]></item>
                <item name="wcf.acp.group.requireMultifactor.description"><![CDATA[Benutzer, die Mitglied dieser Benutzergruppe sind, können die Mehrfaktor-Authentifizierung nicht deaktivieren und können besonders geschützte Bereiche erst betreten, wenn sie die Mehrfaktor-Authentifizierung eingerichtet haben.]]></item>
index 01039fe4cb17a77ed610687d519b025878ef7e0c..7d6850b3a9d73c5fa9a1d95ee9a4a732285d4e22 100644 (file)
@@ -720,7 +720,6 @@ ATTENTION: The messages listed above are greatly shortened. You can view details
                <item name="wcf.acp.group.option.category.user.message.attachment"><![CDATA[Attachments]]></item>
                <item name="wcf.acp.group.option.user.attachment.maxSize"><![CDATA[Maximum Attachment File Size]]></item>
                <item name="wcf.acp.group.option.user.attachment.allowedExtensions"><![CDATA[Allowed Attachment File Extensions]]></item>
-               <item name="wcf.acp.group.option.user.attachment.allowedExtensions.description"><![CDATA[Enter one extension per line.]]></item>
                <item name="wcf.acp.group.option.user.attachment.maxCount"><![CDATA[Maximum Attachments per Message]]></item>
                <item name="wcf.acp.group.option.user.attachment.maxCount.description"><![CDATA[The maximum number of attachments allowed per message.]]></item>
                <item name="wcf.acp.group.option.category.admin.attachment"><![CDATA[Attachments]]></item>
@@ -874,7 +873,6 @@ ATTENTION: The messages listed above are greatly shortened. You can view details
                <item name="wcf.acp.group.option.category.user.message.contactForm"><![CDATA[Contact Form]]></item>
                <item name="wcf.acp.group.option.user.contactForm.attachment.maxSize"><![CDATA[Maximum Attachment File Size]]></item>
                <item name="wcf.acp.group.option.user.contactForm.attachment.allowedExtensions"><![CDATA[Allowed Attachment File Extensions]]></item>
-               <item name="wcf.acp.group.option.user.contactForm.attachment.allowedExtensions.description"><![CDATA[Enter one extension per line.]]></item>
                <item name="wcf.acp.group.option.user.contactForm.attachment.maxCount"><![CDATA[Maximum Attachments per Message]]></item>
                <item name="wcf.acp.group.option.user.profile.canEditUserProfile"><![CDATA[Can edit their profile]]></item>
                <item name="wcf.acp.group.option.user.profile.canHideOnlineStatus"><![CDATA[Can hide their online status]]></item>
@@ -885,7 +883,6 @@ ATTENTION: The messages listed above are greatly shortened. You can view details
                <item name="wcf.acp.group.option.user.signature.attachment.canUpload"><![CDATA[Can Upload Attachments]]></item>
                <item name="wcf.acp.group.option.user.signature.attachment.maxSize"><![CDATA[Maximum Attachment File Size]]></item>
                <item name="wcf.acp.group.option.user.signature.attachment.allowedExtensions"><![CDATA[Allowed Attachment File Extensions]]></item>
-               <item name="wcf.acp.group.option.user.signature.attachment.allowedExtensions.description"><![CDATA[Enter one extension per line.]]></item>
                <item name="wcf.acp.group.option.user.signature.attachment.maxCount"><![CDATA[Maximum Attachments]]></item>
                <item name="wcf.acp.group.requireMultifactor"><![CDATA[Require Multi-factor Authentication]]></item>
                <item name="wcf.acp.group.requireMultifactor.description"><![CDATA[Users that are members of this user group may not disable multi-factor authentication. They will also be required to set up multi-factor authentication before they may enter protected areas.]]></item>