/**
* Provides interface elements to display and review likes.
*
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/Ui/Like/Handler
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Ui/Like/Handler
* @deprecated 5.2 use ReactionHandler instead
*/
-define([
- 'Ajax', 'Core', 'Dictionary', 'Language',
- 'ObjectMap', 'StringUtil', 'Dom/ChangeListener', 'Dom/Util',
- 'Ui/Dialog', 'WoltLabSuite/Core/Ui/User/List', 'User', 'WoltLabSuite/Core/Ui/Reaction/Handler'
-], function (Ajax, Core, Dictionary, Language, ObjectMap, StringUtil, DomChangeListener, DomUtil, UiDialog, UiUserList, User, UiReactionHandler) {
+define(["require", "exports", "tslib", "../../Core", "../../Dom/Change/Listener", "../../Language", "../../StringUtil", "../Reaction/Handler", "../../User"], function (require, exports, tslib_1, Core, Listener_1, Language, StringUtil, Handler_1, User_1) {
"use strict";
- /**
- * @constructor
- */
- function UiLikeHandler(objectType, options) { this.init(objectType, options); }
- UiLikeHandler.prototype = {
+ Core = tslib_1.__importStar(Core);
+ Listener_1 = tslib_1.__importDefault(Listener_1);
+ Language = tslib_1.__importStar(Language);
+ StringUtil = tslib_1.__importStar(StringUtil);
+ Handler_1 = tslib_1.__importDefault(Handler_1);
+ User_1 = tslib_1.__importDefault(User_1);
+ class UiLikeHandler {
/**
* Initializes the like handler.
- *
- * @param {string} objectType object type
- * @param {object} options initialization options
*/
- init: function (objectType, options) {
- if (options.containerSelector === '') {
+ constructor(objectType, opts) {
+ this._containers = new Map();
+ if (!opts.containerSelector) {
throw new Error("[WoltLabSuite/Core/Ui/Like/Handler] Expected a non-empty string for option 'containerSelector'.");
}
- this._containers = new ObjectMap();
- this._details = new ObjectMap();
this._objectType = objectType;
this._options = Core.extend({
// settings
- badgeClassNames: '',
+ badgeClassNames: "",
isSingleItem: false,
markListItemAsActive: false,
renderAsButton: true,
canLikeOwnContent: false,
canViewSummary: false,
// selectors
- badgeContainerSelector: '.messageHeader .messageStatus',
- buttonAppendToSelector: '.messageFooter .messageFooterButtons',
- buttonBeforeSelector: '',
- containerSelector: '',
- summarySelector: '.messageFooterGroup'
- }, options);
- this.initContainers(options, objectType);
- DomChangeListener.add('WoltLabSuite/Core/Ui/Like/Handler-' + objectType, this.initContainers.bind(this));
- new UiReactionHandler(this._objectType, {
+ badgeContainerSelector: ".messageHeader .messageStatus",
+ buttonAppendToSelector: ".messageFooter .messageFooterButtons",
+ buttonBeforeSelector: "",
+ containerSelector: "",
+ summarySelector: ".messageFooterGroup",
+ }, opts);
+ this.initContainers();
+ Listener_1.default.add(`WoltLabSuite/Core/Ui/Like/Handler-${objectType}`, () => this.initContainers());
+ new Handler_1.default(this._objectType, {
containerSelector: this._options.containerSelector,
- summaryListSelector: '.reactionSummaryList'
});
- },
+ }
/**
* Initializes all applicable containers.
*/
- initContainers: function () {
- var element, elements = elBySelAll(this._options.containerSelector), elementData, triggerChange = false;
- for (var i = 0, length = elements.length; i < length; i++) {
- element = elements[i];
+ initContainers() {
+ let triggerChange = false;
+ document.querySelectorAll(this._options.containerSelector).forEach((element) => {
if (this._containers.has(element)) {
- continue;
+ return;
}
- elementData = {
+ const elementData = {
badge: null,
dislikeButton: null,
likeButton: null,
summary: null,
- dislikes: ~~elData(element, 'like-dislikes'),
- liked: ~~elData(element, 'like-liked'),
- likes: ~~elData(element, 'like-likes'),
- objectId: ~~elData(element, 'object-id'),
- users: JSON.parse(elData(element, 'like-users'))
+ dislikes: ~~element.dataset.likeDislikes,
+ liked: ~~element.dataset.likeLiked,
+ likes: ~~element.dataset.likeLikes,
+ objectId: ~~element.dataset.objectId,
+ users: JSON.parse(element.dataset.likeUsers),
};
this._containers.set(element, elementData);
this._buildWidget(element, elementData);
triggerChange = true;
- }
+ });
if (triggerChange) {
- DomChangeListener.trigger();
+ Listener_1.default.trigger();
}
- },
+ }
/**
* Creates the interface elements.
- *
- * @param {Element} element container element
- * @param {object} elementData like data
*/
- _buildWidget: function (element, elementData) {
- // build reaction summary list
- var summaryList, listItem, badgeContainer, isSummaryPosition = true;
- badgeContainer = (this._options.isSingleItem) ? elBySel(this._options.summarySelector) : elBySel(this._options.summarySelector, element);
+ _buildWidget(element, elementData) {
+ let badgeContainer;
+ let isSummaryPosition = true;
+ if (this._options.isSingleItem) {
+ badgeContainer = document.querySelector(this._options.summarySelector);
+ }
+ else {
+ badgeContainer = element.querySelector(this._options.summarySelector);
+ }
if (badgeContainer === null) {
- badgeContainer = (this._options.isSingleItem) ? elBySel(this._options.badgeContainerSelector) : elBySel(this._options.badgeContainerSelector, element);
+ if (this._options.isSingleItem) {
+ badgeContainer = document.querySelector(this._options.badgeContainerSelector);
+ }
+ else {
+ badgeContainer = element.querySelector(this._options.badgeContainerSelector);
+ }
isSummaryPosition = false;
}
if (badgeContainer !== null) {
- summaryList = elCreate('ul');
- summaryList.classList.add('reactionSummaryList');
+ const summaryList = document.createElement("ul");
+ summaryList.classList.add("reactionSummaryList");
if (isSummaryPosition) {
- summaryList.classList.add('likesSummary');
+ summaryList.classList.add("likesSummary");
}
else {
- summaryList.classList.add('reactionSummaryListTiny');
+ summaryList.classList.add("reactionSummaryListTiny");
}
- for (var key in elementData.users) {
- if (key === "reactionTypeID")
- continue;
- if (!REACTION_TYPES.hasOwnProperty(key))
- continue;
- // create element
- var createdElement = elCreate('li');
- createdElement.className = 'reactCountButton';
- elData(createdElement, 'reaction-type-id', key);
- var countSpan = elCreate('span');
- countSpan.className = 'reactionCount';
- countSpan.innerHTML = StringUtil.shortUnit(elementData.users[key]);
+ const availableReactions = new Map(Object.entries(window.REACTION_TYPES));
+ Object.entries(elementData.users).forEach(([reactionTypeId, count]) => {
+ const reaction = availableReactions.get(reactionTypeId);
+ if (reactionTypeId === "reactionTypeID" || !reaction) {
+ return;
+ }
+ // create element
+ const createdElement = document.createElement("li");
+ createdElement.className = "reactCountButton";
+ createdElement.setAttribute("reaction-type-id", reactionTypeId);
+ const countSpan = document.createElement("span");
+ countSpan.className = "reactionCount";
+ countSpan.innerHTML = StringUtil.shortUnit(~~count);
createdElement.appendChild(countSpan);
- createdElement.innerHTML = REACTION_TYPES[key].renderedIcon + createdElement.innerHTML;
+ createdElement.innerHTML = reaction.renderedIcon + createdElement.innerHTML;
summaryList.appendChild(createdElement);
- }
+ });
if (isSummaryPosition) {
if (this._options.summaryPrepend) {
- DomUtil.prepend(summaryList, badgeContainer);
+ badgeContainer.insertAdjacentElement("afterbegin", summaryList);
}
else {
- badgeContainer.appendChild(summaryList);
+ badgeContainer.insertAdjacentElement("beforeend", summaryList);
}
}
else {
- if (badgeContainer.nodeName === 'OL' || badgeContainer.nodeName === 'UL') {
- listItem = elCreate('li');
+ if (badgeContainer.nodeName === "OL" || badgeContainer.nodeName === "UL") {
+ const listItem = document.createElement("li");
listItem.appendChild(summaryList);
badgeContainer.appendChild(listItem);
}
elementData.badge = summaryList;
}
// build reaction button
- if (this._options.canLike && (User.userId != elData(element, 'user-id') || this._options.canLikeOwnContent)) {
- var appendTo = (this._options.buttonAppendToSelector) ? ((this._options.isSingleItem) ? elBySel(this._options.buttonAppendToSelector) : elBySel(this._options.buttonAppendToSelector, element)) : null;
- var insertPosition = (this._options.buttonBeforeSelector) ? ((this._options.isSingleItem) ? elBySel(this._options.buttonBeforeSelector) : elBySel(this._options.buttonBeforeSelector, element)) : null;
+ if (this._options.canLike && (User_1.default.userId != ~~element.dataset.userId || this._options.canLikeOwnContent)) {
+ let appendTo = null;
+ if (this._options.buttonAppendToSelector) {
+ if (this._options.isSingleItem) {
+ appendTo = document.querySelector(this._options.buttonAppendToSelector);
+ }
+ else {
+ appendTo = element.querySelector(this._options.buttonAppendToSelector);
+ }
+ }
+ let insertPosition = null;
+ if (this._options.buttonBeforeSelector) {
+ if (this._options.isSingleItem) {
+ insertPosition = document.querySelector(this._options.buttonBeforeSelector);
+ }
+ else {
+ insertPosition = element.querySelector(this._options.buttonBeforeSelector);
+ }
+ }
if (insertPosition === null && appendTo === null) {
throw new Error("Unable to find insert location for like/dislike buttons.");
}
elementData.likeButton = this._createButton(element, elementData.users.reactionTypeID, insertPosition, appendTo);
}
}
- },
+ }
/**
* Creates a reaction button.
- *
- * @param {Element} element container element
- * @param {int} reactionTypeID the reactionTypeID of the current state
- * @param {Element?} insertBefore insert button before given element
- * @param {Element?} appendTo append button to given element
- * @return {Element} button element
*/
- _createButton: function (element, reactionTypeID, insertBefore, appendTo) {
- var title = Language.get('wcf.reactions.react');
- var listItem = elCreate('li');
- listItem.className = 'wcfReactButton';
- var button = elCreate('a');
- button.className = 'jsTooltip reactButton';
+ _createButton(element, reactionTypeID, insertBefore, appendTo) {
+ const title = Language.get("wcf.reactions.react");
+ const listItem = document.createElement("li");
+ listItem.className = "wcfReactButton";
+ const button = document.createElement("a");
+ button.className = "jsTooltip reactButton";
if (this._options.renderAsButton) {
- button.classList.add('button');
+ button.classList.add("button");
}
- button.href = '#';
+ button.href = "#";
button.title = title;
- var icon = elCreate('span');
- icon.className = 'icon icon16 fa-smile-o';
+ const icon = document.createElement("span");
+ icon.className = "icon icon16 fa-smile-o";
if (reactionTypeID === undefined || reactionTypeID == 0) {
- elData(icon, 'reaction-type-id', 0);
+ icon.dataset.reactionTypeId = "0";
}
else {
- elData(button, 'reaction-type-id', reactionTypeID);
+ button.dataset.reactionTypeId = reactionTypeID.toString();
button.classList.add("active");
}
button.appendChild(icon);
- var invisibleText = elCreate("span");
+ const invisibleText = document.createElement("span");
invisibleText.className = "invisible";
invisibleText.innerHTML = title;
button.appendChild(document.createTextNode(" "));
button.appendChild(invisibleText);
listItem.appendChild(button);
if (insertBefore) {
- insertBefore.parentNode.insertBefore(listItem, insertBefore);
+ insertBefore.insertAdjacentElement("beforebegin", listItem);
}
else {
- appendTo.appendChild(listItem);
+ appendTo.insertAdjacentElement("beforeend", listItem);
}
return button;
}
- };
+ }
+ Core.enableLegacyInheritance(UiLikeHandler);
return UiLikeHandler;
});
+++ /dev/null
-/**
- * Provides interface elements to display and review likes.
- *
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/Ui/Like/Handler
- * @deprecated 5.2 use ReactionHandler instead
- */
-define(
- [
- 'Ajax', 'Core', 'Dictionary', 'Language',
- 'ObjectMap', 'StringUtil', 'Dom/ChangeListener', 'Dom/Util',
- 'Ui/Dialog', 'WoltLabSuite/Core/Ui/User/List', 'User', 'WoltLabSuite/Core/Ui/Reaction/Handler'
- ],
- function(
- Ajax, Core, Dictionary, Language,
- ObjectMap, StringUtil, DomChangeListener, DomUtil,
- UiDialog, UiUserList, User, UiReactionHandler
- )
-{
- "use strict";
-
- /**
- * @constructor
- */
- function UiLikeHandler(objectType, options) { this.init(objectType, options); }
- UiLikeHandler.prototype = {
- /**
- * Initializes the like handler.
- *
- * @param {string} objectType object type
- * @param {object} options initialization options
- */
- init: function(objectType, options) {
- if (options.containerSelector === '') {
- throw new Error("[WoltLabSuite/Core/Ui/Like/Handler] Expected a non-empty string for option 'containerSelector'.");
- }
-
- this._containers = new ObjectMap();
- this._details = new ObjectMap();
- this._objectType = objectType;
- this._options = Core.extend({
- // settings
- badgeClassNames: '',
- isSingleItem: false,
- markListItemAsActive: false,
- renderAsButton: true,
- summaryPrepend: true,
- summaryUseIcon: true,
-
- // permissions
- canDislike: false,
- canLike: false,
- canLikeOwnContent: false,
- canViewSummary: false,
-
- // selectors
- badgeContainerSelector: '.messageHeader .messageStatus',
- buttonAppendToSelector: '.messageFooter .messageFooterButtons',
- buttonBeforeSelector: '',
- containerSelector: '',
- summarySelector: '.messageFooterGroup'
- }, options);
-
- this.initContainers(options, objectType);
-
- DomChangeListener.add('WoltLabSuite/Core/Ui/Like/Handler-' + objectType, this.initContainers.bind(this));
-
- new UiReactionHandler(this._objectType, {
- containerSelector: this._options.containerSelector,
- summaryListSelector: '.reactionSummaryList'
- });
- },
-
- /**
- * Initializes all applicable containers.
- */
- initContainers: function() {
- var element, elements = elBySelAll(this._options.containerSelector), elementData, triggerChange = false;
- for (var i = 0, length = elements.length; i < length; i++) {
- element = elements[i];
- if (this._containers.has(element)) {
- continue;
- }
-
- elementData = {
- badge: null,
- dislikeButton: null,
- likeButton: null,
- summary: null,
-
- dislikes: ~~elData(element, 'like-dislikes'),
- liked: ~~elData(element, 'like-liked'),
- likes: ~~elData(element, 'like-likes'),
- objectId: ~~elData(element, 'object-id'),
- users: JSON.parse(elData(element, 'like-users'))
- };
-
- this._containers.set(element, elementData);
- this._buildWidget(element, elementData);
-
- triggerChange = true;
- }
-
- if (triggerChange) {
- DomChangeListener.trigger();
- }
- },
-
- /**
- * Creates the interface elements.
- *
- * @param {Element} element container element
- * @param {object} elementData like data
- */
- _buildWidget: function(element, elementData) {
- // build reaction summary list
- var summaryList, listItem, badgeContainer, isSummaryPosition = true;
- badgeContainer = (this._options.isSingleItem) ? elBySel(this._options.summarySelector) : elBySel(this._options.summarySelector, element);
- if (badgeContainer === null) {
- badgeContainer = (this._options.isSingleItem) ? elBySel(this._options.badgeContainerSelector) : elBySel(this._options.badgeContainerSelector, element);
- isSummaryPosition = false;
- }
-
- if (badgeContainer !== null) {
- summaryList = elCreate('ul');
- summaryList.classList.add('reactionSummaryList');
- if (isSummaryPosition) {
- summaryList.classList.add('likesSummary');
- }
- else {
- summaryList.classList.add('reactionSummaryListTiny');
- }
-
- for (var key in elementData.users) {
- if (key === "reactionTypeID") continue;
- if (!REACTION_TYPES.hasOwnProperty(key)) continue;
-
- // create element
- var createdElement = elCreate('li');
- createdElement.className = 'reactCountButton';
- elData(createdElement, 'reaction-type-id', key);
-
- var countSpan = elCreate('span');
- countSpan.className = 'reactionCount';
- countSpan.innerHTML = StringUtil.shortUnit(elementData.users[key]);
- createdElement.appendChild(countSpan);
-
- createdElement.innerHTML = REACTION_TYPES[key].renderedIcon + createdElement.innerHTML;
-
- summaryList.appendChild(createdElement);
- }
-
- if (isSummaryPosition) {
- if (this._options.summaryPrepend) {
- DomUtil.prepend(summaryList, badgeContainer);
- }
- else {
- badgeContainer.appendChild(summaryList);
- }
- }
- else {
- if (badgeContainer.nodeName === 'OL' || badgeContainer.nodeName === 'UL') {
- listItem = elCreate('li');
- listItem.appendChild(summaryList);
- badgeContainer.appendChild(listItem);
- }
- else {
- badgeContainer.appendChild(summaryList);
- }
- }
-
- elementData.badge = summaryList;
- }
-
- // build reaction button
- if (this._options.canLike && (User.userId != elData(element, 'user-id') || this._options.canLikeOwnContent)) {
- var appendTo = (this._options.buttonAppendToSelector) ? ((this._options.isSingleItem) ? elBySel(this._options.buttonAppendToSelector) : elBySel(this._options.buttonAppendToSelector, element)) : null;
- var insertPosition = (this._options.buttonBeforeSelector) ? ((this._options.isSingleItem) ? elBySel(this._options.buttonBeforeSelector) : elBySel(this._options.buttonBeforeSelector, element)) : null;
- if (insertPosition === null && appendTo === null) {
- throw new Error("Unable to find insert location for like/dislike buttons.");
- }
- else {
- elementData.likeButton = this._createButton(element, elementData.users.reactionTypeID, insertPosition, appendTo);
- }
- }
- },
-
- /**
- * Creates a reaction button.
- *
- * @param {Element} element container element
- * @param {int} reactionTypeID the reactionTypeID of the current state
- * @param {Element?} insertBefore insert button before given element
- * @param {Element?} appendTo append button to given element
- * @return {Element} button element
- */
- _createButton: function(element, reactionTypeID, insertBefore, appendTo) {
- var title = Language.get('wcf.reactions.react');
-
- var listItem = elCreate('li');
- listItem.className = 'wcfReactButton';
-
- var button = elCreate('a');
- button.className = 'jsTooltip reactButton';
- if (this._options.renderAsButton) {
- button.classList.add('button');
- }
-
- button.href = '#';
- button.title = title;
-
- var icon = elCreate('span');
- icon.className = 'icon icon16 fa-smile-o';
-
- if (reactionTypeID === undefined || reactionTypeID == 0) {
- elData(icon, 'reaction-type-id', 0);
- }
- else {
- elData(button, 'reaction-type-id', reactionTypeID);
- button.classList.add("active");
- }
-
- button.appendChild(icon);
-
- var invisibleText = elCreate("span");
- invisibleText.className = "invisible";
- invisibleText.innerHTML = title;
-
- button.appendChild(document.createTextNode(" "));
- button.appendChild(invisibleText);
-
- listItem.appendChild(button);
-
- if (insertBefore) {
- insertBefore.parentNode.insertBefore(listItem, insertBefore);
- }
- else {
- appendTo.appendChild(listItem);
- }
-
- return button;
- }
- };
-
- return UiLikeHandler;
-});
--- /dev/null
+/**
+ * Provides interface elements to display and review likes.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Ui/Like/Handler
+ * @deprecated 5.2 use ReactionHandler instead
+ */
+
+import * as Core from "../../Core";
+import DomChangeListener from "../../Dom/Change/Listener";
+import * as Language from "../../Language";
+import * as StringUtil from "../../StringUtil";
+import UiReactionHandler from "../Reaction/Handler";
+import User from "../../User";
+
+interface LikeHandlerOptions {
+ // settings
+ badgeClassNames: string;
+ isSingleItem: boolean;
+ markListItemAsActive: boolean;
+ renderAsButton: boolean;
+ summaryPrepend: boolean;
+ summaryUseIcon: boolean;
+
+ // permissions
+ canDislike: boolean;
+ canLike: boolean;
+ canLikeOwnContent: boolean;
+ canViewSummary: boolean;
+
+ // selectors
+ badgeContainerSelector: string;
+ buttonAppendToSelector: string;
+ buttonBeforeSelector: string;
+ containerSelector: string;
+ summarySelector: string;
+}
+
+interface LikeUsers {
+ [key: string]: number;
+}
+
+interface ElementData {
+ badge: HTMLUListElement | null;
+ dislikeButton: null;
+ likeButton: HTMLAnchorElement | null;
+ summary: null;
+
+ dislikes: number;
+ liked: number;
+ likes: number;
+ objectId: number;
+ users: LikeUsers;
+}
+
+class UiLikeHandler {
+ protected readonly _containers = new Map<HTMLElement, ElementData>();
+ protected readonly _objectType: string;
+ protected readonly _options: LikeHandlerOptions;
+
+ /**
+ * Initializes the like handler.
+ */
+ constructor(objectType: string, opts: Partial<LikeHandlerOptions>) {
+ if (!opts.containerSelector) {
+ throw new Error(
+ "[WoltLabSuite/Core/Ui/Like/Handler] Expected a non-empty string for option 'containerSelector'.",
+ );
+ }
+
+ this._objectType = objectType;
+ this._options = Core.extend(
+ {
+ // settings
+ badgeClassNames: "",
+ isSingleItem: false,
+ markListItemAsActive: false,
+ renderAsButton: true,
+ summaryPrepend: true,
+ summaryUseIcon: true,
+
+ // permissions
+ canDislike: false,
+ canLike: false,
+ canLikeOwnContent: false,
+ canViewSummary: false,
+
+ // selectors
+ badgeContainerSelector: ".messageHeader .messageStatus",
+ buttonAppendToSelector: ".messageFooter .messageFooterButtons",
+ buttonBeforeSelector: "",
+ containerSelector: "",
+ summarySelector: ".messageFooterGroup",
+ },
+ opts,
+ ) as LikeHandlerOptions;
+
+ this.initContainers();
+
+ DomChangeListener.add(`WoltLabSuite/Core/Ui/Like/Handler-${objectType}`, () => this.initContainers());
+
+ new UiReactionHandler(this._objectType, {
+ containerSelector: this._options.containerSelector,
+ });
+ }
+
+ /**
+ * Initializes all applicable containers.
+ */
+ initContainers(): void {
+ let triggerChange = false;
+
+ document.querySelectorAll(this._options.containerSelector).forEach((element: HTMLElement) => {
+ if (this._containers.has(element)) {
+ return;
+ }
+
+ const elementData = {
+ badge: null,
+ dislikeButton: null,
+ likeButton: null,
+ summary: null,
+
+ dislikes: ~~element.dataset.likeDislikes!,
+ liked: ~~element.dataset.likeLiked!,
+ likes: ~~element.dataset.likeLikes!,
+ objectId: ~~element.dataset.objectId!,
+ users: JSON.parse(element.dataset.likeUsers!),
+ };
+
+ this._containers.set(element, elementData);
+ this._buildWidget(element, elementData);
+
+ triggerChange = true;
+ });
+
+ if (triggerChange) {
+ DomChangeListener.trigger();
+ }
+ }
+
+ /**
+ * Creates the interface elements.
+ */
+ protected _buildWidget(element: HTMLElement, elementData: ElementData): void {
+ let badgeContainer: HTMLElement | null;
+ let isSummaryPosition = true;
+
+ if (this._options.isSingleItem) {
+ badgeContainer = document.querySelector(this._options.summarySelector);
+ } else {
+ badgeContainer = element.querySelector(this._options.summarySelector);
+ }
+
+ if (badgeContainer === null) {
+ if (this._options.isSingleItem) {
+ badgeContainer = document.querySelector(this._options.badgeContainerSelector);
+ } else {
+ badgeContainer = element.querySelector(this._options.badgeContainerSelector);
+ }
+
+ isSummaryPosition = false;
+ }
+
+ if (badgeContainer !== null) {
+ const summaryList = document.createElement("ul");
+ summaryList.classList.add("reactionSummaryList");
+ if (isSummaryPosition) {
+ summaryList.classList.add("likesSummary");
+ } else {
+ summaryList.classList.add("reactionSummaryListTiny");
+ }
+
+ const availableReactions = new Map(Object.entries(window.REACTION_TYPES));
+ Object.entries(elementData.users).forEach(([reactionTypeId, count]) => {
+ const reaction = availableReactions.get(reactionTypeId);
+ if (reactionTypeId === "reactionTypeID" || !reaction) {
+ return;
+ }
+
+ // create element
+ const createdElement = document.createElement("li");
+ createdElement.className = "reactCountButton";
+ createdElement.setAttribute("reaction-type-id", reactionTypeId);
+
+ const countSpan = document.createElement("span");
+ countSpan.className = "reactionCount";
+ countSpan.innerHTML = StringUtil.shortUnit(~~count);
+ createdElement.appendChild(countSpan);
+
+ createdElement.innerHTML = reaction.renderedIcon + createdElement.innerHTML;
+
+ summaryList.appendChild(createdElement);
+ });
+
+ if (isSummaryPosition) {
+ if (this._options.summaryPrepend) {
+ badgeContainer.insertAdjacentElement("afterbegin", summaryList);
+ } else {
+ badgeContainer.insertAdjacentElement("beforeend", summaryList);
+ }
+ } else {
+ if (badgeContainer.nodeName === "OL" || badgeContainer.nodeName === "UL") {
+ const listItem = document.createElement("li");
+ listItem.appendChild(summaryList);
+ badgeContainer.appendChild(listItem);
+ } else {
+ badgeContainer.appendChild(summaryList);
+ }
+ }
+
+ elementData.badge = summaryList;
+ }
+
+ // build reaction button
+ if (this._options.canLike && (User.userId != ~~element.dataset.userId! || this._options.canLikeOwnContent)) {
+ let appendTo: HTMLElement | null = null;
+ if (this._options.buttonAppendToSelector) {
+ if (this._options.isSingleItem) {
+ appendTo = document.querySelector(this._options.buttonAppendToSelector);
+ } else {
+ appendTo = element.querySelector(this._options.buttonAppendToSelector);
+ }
+ }
+
+ let insertPosition: HTMLElement | null = null;
+ if (this._options.buttonBeforeSelector) {
+ if (this._options.isSingleItem) {
+ insertPosition = document.querySelector(this._options.buttonBeforeSelector);
+ } else {
+ insertPosition = element.querySelector(this._options.buttonBeforeSelector);
+ }
+ }
+
+ if (insertPosition === null && appendTo === null) {
+ throw new Error("Unable to find insert location for like/dislike buttons.");
+ } else {
+ elementData.likeButton = this._createButton(
+ element,
+ elementData.users.reactionTypeID,
+ insertPosition,
+ appendTo,
+ );
+ }
+ }
+ }
+
+ /**
+ * Creates a reaction button.
+ */
+ protected _createButton(
+ element: HTMLElement,
+ reactionTypeID: number,
+ insertBefore: HTMLElement | null,
+ appendTo: HTMLElement | null,
+ ): HTMLAnchorElement {
+ const title = Language.get("wcf.reactions.react");
+
+ const listItem = document.createElement("li");
+ listItem.className = "wcfReactButton";
+
+ const button = document.createElement("a");
+ button.className = "jsTooltip reactButton";
+ if (this._options.renderAsButton) {
+ button.classList.add("button");
+ }
+
+ button.href = "#";
+ button.title = title;
+
+ const icon = document.createElement("span");
+ icon.className = "icon icon16 fa-smile-o";
+
+ if (reactionTypeID === undefined || reactionTypeID == 0) {
+ icon.dataset.reactionTypeId = "0";
+ } else {
+ button.dataset.reactionTypeId = reactionTypeID.toString();
+ button.classList.add("active");
+ }
+
+ button.appendChild(icon);
+
+ const invisibleText = document.createElement("span");
+ invisibleText.className = "invisible";
+ invisibleText.innerHTML = title;
+
+ button.appendChild(document.createTextNode(" "));
+ button.appendChild(invisibleText);
+
+ listItem.appendChild(button);
+
+ if (insertBefore) {
+ insertBefore.insertAdjacentElement("beforebegin", listItem);
+ } else {
+ appendTo!.insertAdjacentElement("beforeend", listItem);
+ }
+
+ return button;
+ }
+}
+
+Core.enableLegacyInheritance(UiLikeHandler);
+
+export = UiLikeHandler;
/**
* Initializes the reaction handler.
*/
- constructor(objectType: string, opts: ReactionHandlerOptions) {
+ constructor(objectType: string, opts: Partial<ReactionHandlerOptions>) {
if (!opts.containerSelector) {
throw new Error(
"[WoltLabSuite/Core/Ui/Reaction/Handler] Expected a non-empty string for option 'containerSelector'.",