From a1327a49309633691e10330af285ee3f44d09f50 Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Sat, 12 Dec 2020 15:35:48 +0100 Subject: [PATCH] Convert `Form/Builder/Field/Controller/Rating` to TypeScript --- .../Form/Builder/Field/Controller/Rating.js | 149 +++++++--------- .../Form/Builder/Field/Controller/Rating.js | 159 ------------------ .../Form/Builder/Field/Controller/Rating.ts | 133 +++++++++++++++ 3 files changed, 194 insertions(+), 247 deletions(-) delete mode 100644 wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js create mode 100644 wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.ts diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js index 2cd528811f..d369c6c661 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js @@ -1,137 +1,110 @@ /** * Handles the JavaScript part of the rating form field. * - * @author Matthias Schmidt - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @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 + * @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 index 2d6a992a68..0000000000 --- a/wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.js +++ /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 - * @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 index 0000000000..38d2009ca4 --- /dev/null +++ b/wcfsetup/install/files/ts/WoltLabSuite/Core/Form/Builder/Field/Controller/Rating.ts @@ -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 + * @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; + + 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; -- 2.20.1