Simplify and convert the rating form field
authorAlexander Ebert <ebert@woltlab.com>
Thu, 18 Aug 2022 16:41:28 +0000 (18:41 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 18 Aug 2022 16:41:28 +0000 (18:41 +0200)
com.woltlab.wcf/templates/__ratingFormField.tpl
ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.ts
wcfsetup/install/files/acp/templates/__ratingFormField.tpl
wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js
wcfsetup/install/files/lib/system/form/builder/field/RatingFormField.class.php
wcfsetup/install/files/style/ui/rating.scss

index cbf631a560e053d14f4c56977e8ad2c186ef214e..f7938e7ba9186036665363b46c25a42b5f0f45cb 100644 (file)
@@ -1,9 +1,21 @@
 <ul class="ratingList jsOnly">
        {foreach from=$field->getRatings() item=rating}
-               <li data-rating="{@$rating}"><span class="icon icon24 {if $rating <= $field->getValue()}{implode from=$field->getActiveCssClasses() item=cssClass glue=' '}{@$cssClass}{/implode}{else}{implode from=$field->getDefaultCssClasses() item=cssClass glue=' '}{@$cssClass}{/implode}{/if} pointer jsTooltip" title="{lang maximumRating=$field->getMaximum()}wcf.form.field.rating.ratingTitle{/lang}"></span></li>
+               <li data-rating="{@$rating}">
+                       <button type="button" class="jsTooltip" title="{lang maximumRating=$field->getMaximum()}wcf.form.field.rating.ratingTitle{/lang}">
+                               {if $rating <= $field->getValue()}
+                                       {icon size=24 name='star' type='solid'}
+                               {else}
+                                       {icon size=24 name='star'}
+                               {/if}
+                       </button>
+               </li>
        {/foreach}
        {if $field->isNullable()}
-               <li class="ratingMetaButton" data-action="removeRating"><span class="icon icon24 fa-times pointer jsTooltip" title="{lang}wcf.form.field.rating.removeRating{/lang}"></span></li>
+               <li class="ratingMetaButton" data-action="removeRating">
+                       <button type="button" class="jsTooltip" title="{lang}wcf.form.field.rating.removeRating{/lang}">
+                               {icon size=24 name='xmark'}
+                       </button>
+               </li>
        {/if}
 </ul>
 <noscript>
@@ -18,9 +30,7 @@
        require(['WoltLabSuite/Core/Form/Builder/Field/Controller/Rating'], function(FormBuilderFieldRating) {
                new FormBuilderFieldRating(
                        '{@$field->getPrefixedId()}',
-                       {if $field->getValue() !== null}{@$field->getValue()}{else}''{/if},
-                       [ {implode from=$field->getActiveCssClasses() item=cssClass}'{@$cssClass}'{/implode} ],
-                       [ {implode from=$field->getDefaultCssClasses() item=cssClass}'{@$cssClass}'{/implode} ]
+                       {if $field->getValue() !== null}{@$field->getValue()}{else}''{/if}
                );
        });
 </script>
index ec5e8da63a1de83af01ca91949bfd2068a7b49e4..f0b378afd02ddf13bd9455847d942293c7d83b63 100644 (file)
@@ -12,13 +12,11 @@ import * as Core from "../../../../Core";
 import * as Environment from "../../../../Environment";
 
 class Rating {
-  protected readonly _activeCssClasses: string[];
-  protected readonly _defaultCssClasses: string[];
   protected readonly _field: HTMLElement;
   protected readonly _input: HTMLInputElement;
   protected readonly _ratingElements: Map<string, HTMLElement>;
 
-  constructor(fieldId: string, value: string, activeCssClasses: string[], defaultCssClasses: string[]) {
+  constructor(fieldId: string, value: string) {
     this._field = document.getElementById(fieldId + "Container")!;
     if (this._field === null) {
       throw new Error("Unknown field with id '" + fieldId + "'");
@@ -31,9 +29,6 @@ class Rating {
     this._input.value = value;
     this._field.appendChild(this._input);
 
-    this._activeCssClasses = activeCssClasses;
-    this._defaultCssClasses = defaultCssClasses;
-
     this._ratingElements = new Map();
 
     const ratingList = this._field.querySelector(".ratingList")!;
@@ -73,7 +68,7 @@ class Rating {
     const currentRating = target.dataset.rating!;
 
     this._ratingElements.forEach((ratingElement, rating) => {
-      const icon = ratingElement.getElementsByClassName("icon")[0]! as HTMLElement;
+      const icon = ratingElement.querySelector("fa-icon")!;
 
       this._toggleIcon(icon, ~~rating <= ~~currentRating);
     });
@@ -85,7 +80,7 @@ class Rating {
    */
   protected _listItemMouseLeave(): void {
     this._ratingElements.forEach((ratingElement) => {
-      const icon = ratingElement.getElementsByClassName("icon")[0]! as HTMLElement;
+      const icon = ratingElement.querySelector("fa-icon")!;
 
       this._toggleIcon(icon, false);
     });
@@ -108,7 +103,7 @@ class Rating {
    */
   protected _restoreRating(): void {
     this._ratingElements.forEach((ratingElement, rating) => {
-      const icon = ratingElement.getElementsByClassName("icon")[0]! as HTMLElement;
+      const icon = ratingElement.querySelector("fa-icon")!;
 
       this._toggleIcon(icon, ~~rating <= ~~this._input.value);
     });
@@ -117,13 +112,11 @@ class Rating {
   /**
    * Toggles the state of the given icon based on the given state parameter.
    */
-  protected _toggleIcon(icon: HTMLElement, active = false): void {
+  protected _toggleIcon(icon: FaIcon, active = false): void {
     if (active) {
-      icon.classList.remove(...this._defaultCssClasses);
-      icon.classList.add(...this._activeCssClasses);
+      icon.setIcon("star", true);
     } else {
-      icon.classList.remove(...this._activeCssClasses);
-      icon.classList.add(...this._defaultCssClasses);
+      icon.setIcon("star");
     }
   }
 }
index cbf631a560e053d14f4c56977e8ad2c186ef214e..f7938e7ba9186036665363b46c25a42b5f0f45cb 100644 (file)
@@ -1,9 +1,21 @@
 <ul class="ratingList jsOnly">
        {foreach from=$field->getRatings() item=rating}
-               <li data-rating="{@$rating}"><span class="icon icon24 {if $rating <= $field->getValue()}{implode from=$field->getActiveCssClasses() item=cssClass glue=' '}{@$cssClass}{/implode}{else}{implode from=$field->getDefaultCssClasses() item=cssClass glue=' '}{@$cssClass}{/implode}{/if} pointer jsTooltip" title="{lang maximumRating=$field->getMaximum()}wcf.form.field.rating.ratingTitle{/lang}"></span></li>
+               <li data-rating="{@$rating}">
+                       <button type="button" class="jsTooltip" title="{lang maximumRating=$field->getMaximum()}wcf.form.field.rating.ratingTitle{/lang}">
+                               {if $rating <= $field->getValue()}
+                                       {icon size=24 name='star' type='solid'}
+                               {else}
+                                       {icon size=24 name='star'}
+                               {/if}
+                       </button>
+               </li>
        {/foreach}
        {if $field->isNullable()}
-               <li class="ratingMetaButton" data-action="removeRating"><span class="icon icon24 fa-times pointer jsTooltip" title="{lang}wcf.form.field.rating.removeRating{/lang}"></span></li>
+               <li class="ratingMetaButton" data-action="removeRating">
+                       <button type="button" class="jsTooltip" title="{lang}wcf.form.field.rating.removeRating{/lang}">
+                               {icon size=24 name='xmark'}
+                       </button>
+               </li>
        {/if}
 </ul>
 <noscript>
@@ -18,9 +30,7 @@
        require(['WoltLabSuite/Core/Form/Builder/Field/Controller/Rating'], function(FormBuilderFieldRating) {
                new FormBuilderFieldRating(
                        '{@$field->getPrefixedId()}',
-                       {if $field->getValue() !== null}{@$field->getValue()}{else}''{/if},
-                       [ {implode from=$field->getActiveCssClasses() item=cssClass}'{@$cssClass}'{/implode} ],
-                       [ {implode from=$field->getDefaultCssClasses() item=cssClass}'{@$cssClass}'{/implode} ]
+                       {if $field->getValue() !== null}{@$field->getValue()}{else}''{/if}
                );
        });
 </script>
index d369c6c661134727cd715007251e03068057d6af..72ff393a3298b75717f5028444d48a98ae9c5017 100644 (file)
@@ -12,7 +12,7 @@ define(["require", "exports", "tslib", "../../../../Core", "../../../../Environm
     Core = tslib_1.__importStar(Core);
     Environment = tslib_1.__importStar(Environment);
     class Rating {
-        constructor(fieldId, value, activeCssClasses, defaultCssClasses) {
+        constructor(fieldId, value) {
             this._field = document.getElementById(fieldId + "Container");
             if (this._field === null) {
                 throw new Error("Unknown field with id '" + fieldId + "'");
@@ -23,8 +23,6 @@ define(["require", "exports", "tslib", "../../../../Core", "../../../../Environm
             this._input.type = "hidden";
             this._input.value = value;
             this._field.appendChild(this._input);
-            this._activeCssClasses = activeCssClasses;
-            this._defaultCssClasses = defaultCssClasses;
             this._ratingElements = new Map();
             const ratingList = this._field.querySelector(".ratingList");
             ratingList.addEventListener("mouseleave", () => this._restoreRating());
@@ -58,7 +56,7 @@ define(["require", "exports", "tslib", "../../../../Core", "../../../../Environm
             const target = event.currentTarget;
             const currentRating = target.dataset.rating;
             this._ratingElements.forEach((ratingElement, rating) => {
-                const icon = ratingElement.getElementsByClassName("icon")[0];
+                const icon = ratingElement.querySelector("fa-icon");
                 this._toggleIcon(icon, ~~rating <= ~~currentRating);
             });
         }
@@ -68,7 +66,7 @@ define(["require", "exports", "tslib", "../../../../Core", "../../../../Environm
          */
         _listItemMouseLeave() {
             this._ratingElements.forEach((ratingElement) => {
-                const icon = ratingElement.getElementsByClassName("icon")[0];
+                const icon = ratingElement.querySelector("fa-icon");
                 this._toggleIcon(icon, false);
             });
         }
@@ -87,7 +85,7 @@ define(["require", "exports", "tslib", "../../../../Core", "../../../../Environm
          */
         _restoreRating() {
             this._ratingElements.forEach((ratingElement, rating) => {
-                const icon = ratingElement.getElementsByClassName("icon")[0];
+                const icon = ratingElement.querySelector("fa-icon");
                 this._toggleIcon(icon, ~~rating <= ~~this._input.value);
             });
         }
@@ -96,12 +94,10 @@ define(["require", "exports", "tslib", "../../../../Core", "../../../../Environm
          */
         _toggleIcon(icon, active = false) {
             if (active) {
-                icon.classList.remove(...this._defaultCssClasses);
-                icon.classList.add(...this._activeCssClasses);
+                icon.setIcon("star", true);
             }
             else {
-                icon.classList.remove(...this._activeCssClasses);
-                icon.classList.add(...this._defaultCssClasses);
+                icon.setIcon("star");
             }
         }
     }
index e9e59480d3f54ff72aa4ecee925e606fe0939413..9fd2ab42da369239a6219d46e9c5054aefc81641 100644 (file)
@@ -13,9 +13,6 @@ use wcf\system\WCF;
  * the the field is not nullable, the minimum value will be automatically set when the field's value
  * is requested the first time.
  *
- * By default, the active rating state is represented by orange stars and the default state by white
- * stars with a black border.
- *
  * This field uses the `wcf.form.field.rating` language item as the default form field label and has
  * a minimum rating of `1` and a maximum rating of `5`.
  *
@@ -41,18 +38,6 @@ class RatingFormField extends AbstractFormField implements
     }
     use TNullableFormField;
 
-    /**
-     * CSS classes for the active state of the rating elements
-     * @var string[]
-     */
-    protected $activeCssClasses = ['fa-star', 'orange'];
-
-    /**
-     * CSS classes for the default state of the rating elements
-     * @var string[]
-     */
-    protected $defaultCssClasses = ['fa-star-o'];
-
     /**
      * @inheritDoc
      */
@@ -73,70 +58,6 @@ class RatingFormField extends AbstractFormField implements
         $this->maximum(5);
     }
 
-    /**
-     * Sets the CSS classes for the active state of the rating elements.
-     *
-     * @param string[] $cssClasses active state CSS classes
-     * @return  static              this form field
-     * @throws  \InvalidArgumentException   if no or invalid CSS classes are given
-     */
-    public function activeCssClasses(array $cssClasses)
-    {
-        if (empty($cssClasses)) {
-            throw new \InvalidArgumentException("No css classes for active state given for field '{$this->getId()}'.");
-        }
-
-        foreach ($cssClasses as $cssClass) {
-            static::validateClass($cssClass);
-        }
-
-        $this->activeCssClasses = $cssClasses;
-
-        return $this;
-    }
-
-    /**
-     * Sets the CSS classes for the default state of the rating elements.
-     *
-     * @param string[] $cssClasses default state CSS classes
-     * @return  static              this form field
-     * @throws  \InvalidArgumentException   if no or invalid CSS classes are given
-     */
-    public function defaultCssClasses(array $cssClasses)
-    {
-        if (empty($cssClasses)) {
-            throw new \InvalidArgumentException("No css classes for default state given for field '{$this->getId()}'.");
-        }
-
-        foreach ($cssClasses as $cssClass) {
-            static::validateClass($cssClass);
-        }
-
-        $this->defaultCssClasses = $cssClasses;
-
-        return $this;
-    }
-
-    /**
-     * Returns the CSS classes for the active state of the rating elements.
-     *
-     * @return  string[]
-     */
-    public function getActiveCssClasses()
-    {
-        return $this->activeCssClasses;
-    }
-
-    /**
-     * Returns the CSS classes for the default state of the rating elements.
-     *
-     * @return  string[]
-     */
-    public function getDefaultCssClasses()
-    {
-        return $this->defaultCssClasses;
-    }
-
     /**
      * Returns the sorted list of possible ratings used to generate the form field's html code.
      *
index a275b60fa302a5c03756d9a7bcd398df0dc9fc88..3d4c9363234894bc1ec2dd419e903e1a448ee8de 100644 (file)
@@ -4,4 +4,8 @@
        > li {
                display: inline-block;
        }
+
+       fa-icon[name="star"][solid] {
+               color: #f90;
+       }
 }