Convert `Form/Builder/Field/Controller/Rating` to TypeScript
authorMatthias Schmidt <gravatronics@live.com>
Sat, 12 Dec 2020 14:35:48 +0000 (15:35 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Tue, 15 Dec 2020 17:23:05 +0000 (18:23 +0100)
wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js
wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js [deleted file]
wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.ts [new file with mode: 0644]

index 2cd528811f36ae89364f77bdf72169e86f2d1b05..d369c6c661134727cd715007251e03068057d6af 100644 (file)
 /**
  * Handles the JavaScript part of the rating form field.
  *
- * @author     Matthias Schmidt
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Form/Builder/Field/Controller/Rating
- * @since      5.2
+ * @author  Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Form/Builder/Field/Controller/Rating
+ * @since 5.2
  */
-define(['Dictionary', 'Environment'], function (Dictionary, Environment) {
+define(["require", "exports", "tslib", "../../../../Core", "../../../../Environment"], function (require, exports, tslib_1, Core, Environment) {
     "use strict";
-    /**
-     * @constructor
-     */
-    function FormBuilderFieldRating(fieldId, value, activeCssClasses, defaultCssClasses) {
-        this.init(fieldId, value, activeCssClasses, defaultCssClasses);
-    }
-    ;
-    FormBuilderFieldRating.prototype = {
-        /**
-         * Initializes the rating form field.
-         *
-         * @param      {string}        fieldId                 id of the relevant form builder field
-         * @param      {integer}       value                   current value of the field
-         * @param      {string[]}      activeCssClasses        CSS classes for the active state of rating elements
-         * @param      {string[]}      defaultCssClasses       CSS classes for the default state of rating elements
-         */
-        init: function (fieldId, value, activeCssClasses, defaultCssClasses) {
-            this._field = elBySel('#' + fieldId + 'Container');
+    Core = tslib_1.__importStar(Core);
+    Environment = tslib_1.__importStar(Environment);
+    class Rating {
+        constructor(fieldId, value, activeCssClasses, defaultCssClasses) {
+            this._field = document.getElementById(fieldId + "Container");
             if (this._field === null) {
                 throw new Error("Unknown field with id '" + fieldId + "'");
             }
-            this._input = elCreate('input');
+            this._input = document.createElement("input");
             this._input.id = fieldId;
             this._input.name = fieldId;
-            this._input.type = 'hidden';
+            this._input.type = "hidden";
             this._input.value = value;
             this._field.appendChild(this._input);
             this._activeCssClasses = activeCssClasses;
             this._defaultCssClasses = defaultCssClasses;
-            this._ratingElements = new Dictionary();
-            var ratingList = elBySel('.ratingList', this._field);
-            ratingList.addEventListener('mouseleave', this._restoreRating.bind(this));
-            elBySelAll('li', ratingList, function (listItem) {
-                if (listItem.classList.contains('ratingMetaButton')) {
-                    listItem.addEventListener('click', this._metaButtonClick.bind(this));
-                    listItem.addEventListener('mouseenter', this._restoreRating.bind(this));
+            this._ratingElements = new Map();
+            const ratingList = this._field.querySelector(".ratingList");
+            ratingList.addEventListener("mouseleave", () => this._restoreRating());
+            ratingList.querySelectorAll("li").forEach((listItem) => {
+                if (listItem.classList.contains("ratingMetaButton")) {
+                    listItem.addEventListener("click", (ev) => this._metaButtonClick(ev));
+                    listItem.addEventListener("mouseenter", () => this._restoreRating());
                 }
                 else {
-                    this._ratingElements.set(~~elData(listItem, 'rating'), listItem);
-                    listItem.addEventListener('click', this._listItemClick.bind(this));
-                    listItem.addEventListener('mouseenter', this._listItemMouseEnter.bind(this));
-                    listItem.addEventListener('mouseleave', this._listItemMouseLeave.bind(this));
+                    this._ratingElements.set(listItem.dataset.rating, listItem);
+                    listItem.addEventListener("click", (ev) => this._listItemClick(ev));
+                    listItem.addEventListener("mouseenter", (ev) => this._listItemMouseEnter(ev));
+                    listItem.addEventListener("mouseleave", () => this._listItemMouseLeave());
                 }
-            }.bind(this));
-        },
+            });
+        }
         /**
          * Saves the rating associated with the clicked rating element.
-         *
-         * @param      {Event}         event   rating element `click` event
          */
-        _listItemClick: function (event) {
-            this._input.value = ~~elData(event.currentTarget, 'rating');
-            if (Environment.platform() !== 'desktop') {
+        _listItemClick(event) {
+            const target = event.currentTarget;
+            this._input.value = target.dataset.rating;
+            if (Environment.platform() !== "desktop") {
                 this._restoreRating();
             }
-        },
+        }
         /**
          * Updates the rating UI when hovering over a rating element.
-         *
-         * @param      {Event}         event   rating element `mouseenter` event
          */
-        _listItemMouseEnter: function (event) {
-            var currentRating = elData(event.currentTarget, 'rating');
-            this._ratingElements.forEach(function (ratingElement, rating) {
-                var icon = elByClass('icon', ratingElement)[0];
+        _listItemMouseEnter(event) {
+            const target = event.currentTarget;
+            const currentRating = target.dataset.rating;
+            this._ratingElements.forEach((ratingElement, rating) => {
+                const icon = ratingElement.getElementsByClassName("icon")[0];
                 this._toggleIcon(icon, ~~rating <= ~~currentRating);
-            }.bind(this));
-        },
+            });
+        }
         /**
          * Updates the rating UI when leaving a rating element by changing all rating elements
          * to their default state.
          */
-        _listItemMouseLeave: function () {
-            this._ratingElements.forEach(function (ratingElement) {
-                var icon = elByClass('icon', ratingElement)[0];
+        _listItemMouseLeave() {
+            this._ratingElements.forEach((ratingElement) => {
+                const icon = ratingElement.getElementsByClassName("icon")[0];
                 this._toggleIcon(icon, false);
-            }.bind(this));
-        },
+            });
+        }
         /**
          * Handles clicks on meta buttons.
-         *
-         * @param      {Event}         event   meta button `click` event
          */
-        _metaButtonClick: function (event) {
-            if (elData(event.currentTarget, 'action') === 'removeRating') {
-                this._input.value = '';
+        _metaButtonClick(event) {
+            const target = event.currentTarget;
+            if (target.dataset.action === "removeRating") {
+                this._input.value = "";
                 this._listItemMouseLeave();
             }
-        },
+        }
         /**
          * Updates the rating UI by changing the rating elements to the stored rating state.
          */
-        _restoreRating: function () {
-            this._ratingElements.forEach(function (ratingElement, rating) {
-                var icon = elByClass('icon', ratingElement)[0];
+        _restoreRating() {
+            this._ratingElements.forEach((ratingElement, rating) => {
+                const icon = ratingElement.getElementsByClassName("icon")[0];
                 this._toggleIcon(icon, ~~rating <= ~~this._input.value);
-            }.bind(this));
-        },
+            });
+        }
         /**
          * Toggles the state of the given icon based on the given state parameter.
-         *
-         * @param      {HTMLElement}   icon            toggled icon
-         * @param      {boolean}       active          is `true` if icon will be changed to `active` state, otherwise changed to `default` state
          */
-        _toggleIcon: function (icon, active) {
-            active = active || false;
+        _toggleIcon(icon, active = false) {
             if (active) {
-                for (var i = 0; i < this._defaultCssClasses.length; i++) {
-                    icon.classList.remove(this._defaultCssClasses[i]);
-                }
-                for (var i = 0; i < this._activeCssClasses.length; i++) {
-                    icon.classList.add(this._activeCssClasses[i]);
-                }
+                icon.classList.remove(...this._defaultCssClasses);
+                icon.classList.add(...this._activeCssClasses);
             }
             else {
-                for (var i = 0; i < this._activeCssClasses.length; i++) {
-                    icon.classList.remove(this._activeCssClasses[i]);
-                }
-                for (var i = 0; i < this._defaultCssClasses.length; i++) {
-                    icon.classList.add(this._defaultCssClasses[i]);
-                }
+                icon.classList.remove(...this._activeCssClasses);
+                icon.classList.add(...this._defaultCssClasses);
             }
         }
-    };
-    return FormBuilderFieldRating;
+    }
+    Core.enableLegacyInheritance(Rating);
+    return Rating;
 });
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js
deleted file mode 100644 (file)
index 2d6a992..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * Handles the JavaScript part of the rating form field.
- * 
- * @author     Matthias Schmidt
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Form/Builder/Field/Controller/Rating
- * @since      5.2
- */
-define(['Dictionary', 'Environment'], function(Dictionary, Environment) {
-       "use strict";
-       
-       /**
-        * @constructor
-        */
-       function FormBuilderFieldRating(fieldId, value, activeCssClasses, defaultCssClasses) {
-               this.init(fieldId, value, activeCssClasses, defaultCssClasses);
-       };
-       FormBuilderFieldRating.prototype = {
-               /**
-                * Initializes the rating form field.
-                * 
-                * @param       {string}        fieldId                 id of the relevant form builder field
-                * @param       {integer}       value                   current value of the field
-                * @param       {string[]}      activeCssClasses        CSS classes for the active state of rating elements
-                * @param       {string[]}      defaultCssClasses       CSS classes for the default state of rating elements
-                */
-               init: function(fieldId, value, activeCssClasses, defaultCssClasses) {
-                       this._field = elBySel('#' + fieldId + 'Container');
-                       if (this._field === null) {
-                               throw new Error("Unknown field with id '" + fieldId + "'");
-                       }
-                       
-                       this._input = elCreate('input');
-                       this._input.id = fieldId;
-                       this._input.name = fieldId;
-                       this._input.type = 'hidden';
-                       this._input.value = value;
-                       this._field.appendChild(this._input);
-                       
-                       this._activeCssClasses = activeCssClasses;
-                       this._defaultCssClasses = defaultCssClasses;
-                       
-                       this._ratingElements = new Dictionary();
-                       
-                       var ratingList = elBySel('.ratingList', this._field);
-                       ratingList.addEventListener('mouseleave', this._restoreRating.bind(this));
-                       
-                       elBySelAll('li', ratingList, function(listItem) {
-                               if (listItem.classList.contains('ratingMetaButton')) {
-                                       listItem.addEventListener('click', this._metaButtonClick.bind(this));
-                                       listItem.addEventListener('mouseenter', this._restoreRating.bind(this));
-                               }
-                               else {
-                                       this._ratingElements.set(~~elData(listItem, 'rating'), listItem);
-                                       
-                                       listItem.addEventListener('click', this._listItemClick.bind(this));
-                                       listItem.addEventListener('mouseenter', this._listItemMouseEnter.bind(this));
-                                       listItem.addEventListener('mouseleave', this._listItemMouseLeave.bind(this));
-                               }
-                       }.bind(this));
-               },
-               
-               /**
-                * Saves the rating associated with the clicked rating element.
-                * 
-                * @param       {Event}         event   rating element `click` event
-                */
-               _listItemClick: function(event) {
-                       this._input.value = ~~elData(event.currentTarget, 'rating');
-                       
-                       if (Environment.platform() !== 'desktop') {
-                               this._restoreRating();
-                       }
-               },
-               
-               /**
-                * Updates the rating UI when hovering over a rating element.
-                * 
-                * @param       {Event}         event   rating element `mouseenter` event
-                */
-               _listItemMouseEnter: function(event) {
-                       var currentRating = elData(event.currentTarget, 'rating');
-                       
-                       this._ratingElements.forEach(function(ratingElement, rating) {
-                               var icon = elByClass('icon', ratingElement)[0];
-                               
-                               this._toggleIcon(icon, ~~rating <= ~~currentRating);
-                       }.bind(this));
-               },
-               
-               /**
-                * Updates the rating UI when leaving a rating element by changing all rating elements
-                * to their default state.
-                */
-               _listItemMouseLeave: function() {
-                       this._ratingElements.forEach(function(ratingElement) {
-                               var icon = elByClass('icon', ratingElement)[0];
-                               
-                               this._toggleIcon(icon, false);
-                       }.bind(this));
-               },
-               
-               /**
-                * Handles clicks on meta buttons.
-                * 
-                * @param       {Event}         event   meta button `click` event
-                */
-               _metaButtonClick: function(event) {
-                       if (elData(event.currentTarget, 'action') === 'removeRating') {
-                               this._input.value = '';
-                               
-                               this._listItemMouseLeave();
-                       }
-               },
-               
-               /**
-                * Updates the rating UI by changing the rating elements to the stored rating state.
-                */
-               _restoreRating: function() {
-                       this._ratingElements.forEach(function(ratingElement, rating) {
-                               var icon = elByClass('icon', ratingElement)[0];
-                               
-                               this._toggleIcon(icon, ~~rating <= ~~this._input.value);
-                       }.bind(this));
-               },
-               
-               /**
-                * Toggles the state of the given icon based on the given state parameter.
-                * 
-                * @param       {HTMLElement}   icon            toggled icon
-                * @param       {boolean}       active          is `true` if icon will be changed to `active` state, otherwise changed to `default` state
-                */
-               _toggleIcon: function(icon, active) {
-                       active = active || false;
-                       
-                       if (active) {
-                               for (var i = 0; i < this._defaultCssClasses.length; i++) {
-                                       icon.classList.remove(this._defaultCssClasses[i]);
-                               }
-                               
-                               for (var i = 0; i < this._activeCssClasses.length; i++) {
-                                       icon.classList.add(this._activeCssClasses[i]);
-                               }
-                       }
-                       else {
-                               for (var i = 0; i < this._activeCssClasses.length; i++) {
-                                       icon.classList.remove(this._activeCssClasses[i]);
-                               }
-                               
-                               for (var i = 0; i < this._defaultCssClasses.length; i++) {
-                                       icon.classList.add(this._defaultCssClasses[i]);
-                               }
-                       }
-               }
-       };
-       
-       return FormBuilderFieldRating;
-});
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.ts
new file mode 100644 (file)
index 0000000..38d2009
--- /dev/null
@@ -0,0 +1,133 @@
+/**
+ * Handles the JavaScript part of the rating form field.
+ *
+ * @author  Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Form/Builder/Field/Controller/Rating
+ * @since 5.2
+ */
+
+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[]) {
+    this._field = document.getElementById(fieldId + "Container")!;
+    if (this._field === null) {
+      throw new Error("Unknown field with id '" + fieldId + "'");
+    }
+
+    this._input = document.createElement("input");
+    this._input.id = fieldId;
+    this._input.name = fieldId;
+    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());
+
+    ratingList.querySelectorAll("li").forEach((listItem) => {
+      if (listItem.classList.contains("ratingMetaButton")) {
+        listItem.addEventListener("click", (ev) => this._metaButtonClick(ev));
+        listItem.addEventListener("mouseenter", () => this._restoreRating());
+      } else {
+        this._ratingElements.set(listItem.dataset.rating!, listItem);
+
+        listItem.addEventListener("click", (ev) => this._listItemClick(ev));
+        listItem.addEventListener("mouseenter", (ev) => this._listItemMouseEnter(ev));
+        listItem.addEventListener("mouseleave", () => this._listItemMouseLeave());
+      }
+    });
+  }
+
+  /**
+   * Saves the rating associated with the clicked rating element.
+   */
+  _listItemClick(event: Event): void {
+    const target = event.currentTarget as HTMLElement;
+    this._input.value = target.dataset.rating!;
+
+    if (Environment.platform() !== "desktop") {
+      this._restoreRating();
+    }
+  }
+
+  /**
+   * Updates the rating UI when hovering over a rating element.
+   */
+  _listItemMouseEnter(event: Event): void {
+    const target = event.currentTarget as HTMLElement;
+    const currentRating = target.dataset.rating!;
+
+    this._ratingElements.forEach((ratingElement, rating) => {
+      const icon = ratingElement.getElementsByClassName("icon")[0]! as HTMLElement;
+
+      this._toggleIcon(icon, ~~rating <= ~~currentRating);
+    });
+  }
+
+  /**
+   * Updates the rating UI when leaving a rating element by changing all rating elements
+   * to their default state.
+   */
+  _listItemMouseLeave(): void {
+    this._ratingElements.forEach((ratingElement) => {
+      const icon = ratingElement.getElementsByClassName("icon")[0]! as HTMLElement;
+
+      this._toggleIcon(icon, false);
+    });
+  }
+
+  /**
+   * Handles clicks on meta buttons.
+   */
+  _metaButtonClick(event: Event): void {
+    const target = event.currentTarget as HTMLElement;
+    if (target.dataset.action === "removeRating") {
+      this._input.value = "";
+
+      this._listItemMouseLeave();
+    }
+  }
+
+  /**
+   * Updates the rating UI by changing the rating elements to the stored rating state.
+   */
+  _restoreRating(): void {
+    this._ratingElements.forEach((ratingElement, rating) => {
+      const icon = ratingElement.getElementsByClassName("icon")[0]! as HTMLElement;
+
+      this._toggleIcon(icon, ~~rating <= ~~this._input.value);
+    });
+  }
+
+  /**
+   * Toggles the state of the given icon based on the given state parameter.
+   */
+  _toggleIcon(icon: HTMLElement, active = false): void {
+    if (active) {
+      icon.classList.remove(...this._defaultCssClasses);
+      icon.classList.add(...this._activeCssClasses);
+    } else {
+      icon.classList.remove(...this._activeCssClasses);
+      icon.classList.add(...this._defaultCssClasses);
+    }
+  }
+}
+
+Core.enableLegacyInheritance(Rating);
+
+export = Rating;