From d0627c12484f7a823e3752c3c2ead159d89e7364 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Joshua=20R=C3=BCsweg?= Date: Mon, 27 May 2019 13:38:05 +0200 Subject: [PATCH] Fix reactions for non unique containers Sometimes it is necessary to reload object containers (e.g. if something is sorted via JavaScript and the elements have to be reloaded in the background). This was not possible with the implementation, each object could exist only once in the DOM. See #2508 --- .../Core/Ui/Reaction/CountButtons.js | 96 +++++++++++-------- .../WoltLabSuite/Core/Ui/Reaction/Handler.js | 47 +++++---- 2 files changed, 84 insertions(+), 59 deletions(-) diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/CountButtons.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/CountButtons.js index 34b50dddce..d2211e2283 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/CountButtons.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/CountButtons.js @@ -38,6 +38,7 @@ define( } this._containers = new Dictionary(); + this._objects = new Dictionary(); this._objectType = objectType; this._options = Core.extend({ @@ -64,8 +65,7 @@ define( var element, elements = elBySelAll(this._options.containerSelector), elementData, triggerChange = false, objectId; for (var i = 0, length = elements.length; i < length; i++) { element = elements[i]; - objectId = ~~elData(element, 'object-id'); - if (this._containers.has(objectId)) { + if (this._containers.has(DomUtil.identify(element))) { continue; } @@ -77,9 +77,20 @@ define( element: element }; - this._containers.set(objectId, elementData); + this._containers.set(DomUtil.identify(element), elementData); this._initReactionCountButtons(element, elementData); + if (!this._objects.has(~~elData(element, 'object-id'))) { + var objects = []; + } + else { + var objects = this._objects.get(~~elData(element, 'object-id')); + } + + objects.push(elementData); + + this._objects.set(~~elData(element, 'object-id'), objects); + triggerChange = true; } @@ -95,46 +106,47 @@ define( * @param {object} data */ updateCountButtons: function(objectId, data) { - var summaryList = elBySel(this._options.summaryListSelector, this._containers.get(objectId).element); - - var sortedElements = {}, elements = elBySelAll('li', summaryList); - for (var i = 0, length = elements.length; i < length; i++) { - if (data[elData(elements[i], 'reaction-type-id')] !== undefined) { - sortedElements[elData(elements[i], 'reaction-type-id')] = elements[i]; - } - else { - // reaction has no longer reactions - elRemove(elements[i]); - } - } - - - var triggerChange = false; - Object.keys(data).forEach(function(key) { - if (sortedElements[key] !== undefined) { - var reactionCount = elBySel('.reactionCount', sortedElements[key]); - reactionCount.innerHTML = StringUtil.shortUnit(data[key]); - } - else if (REACTION_TYPES[key] !== undefined) { - // 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(data[key]); - createdElement.appendChild(countSpan); - - createdElement.innerHTML = createdElement.innerHTML + REACTION_TYPES[key].renderedIcon; - - summaryList.appendChild(createdElement); - - this._initReactionCountButton(createdElement, objectId); - - triggerChange = true; + var triggerChange = false; + this._objects.get(objectId).forEach(function(elementData) { + var summaryList = elBySel(this._options.summaryListSelector, elementData.element); + + var sortedElements = {}, elements = elBySelAll('li', summaryList); + for (var i = 0, length = elements.length; i < length; i++) { + if (data[elData(elements[i], 'reaction-type-id')] !== undefined) { + sortedElements[elData(elements[i], 'reaction-type-id')] = elements[i]; + } + else { + // reaction has no longer reactions + elRemove(elements[i]); + } } - }, this); + + Object.keys(data).forEach(function(key) { + if (sortedElements[key] !== undefined) { + var reactionCount = elBySel('.reactionCount', sortedElements[key]); + reactionCount.innerHTML = StringUtil.shortUnit(data[key]); + } + else if (REACTION_TYPES[key] !== undefined) { + // 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(data[key]); + createdElement.appendChild(countSpan); + + createdElement.innerHTML = createdElement.innerHTML + REACTION_TYPES[key].renderedIcon; + + summaryList.appendChild(createdElement); + + this._initReactionCountButton(createdElement, objectId); + + triggerChange = true; + } + }, this); + }.bind(this)); if (triggerChange) { DomChangeListener.trigger(); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/Handler.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/Handler.js index 73006a2ede..a9b7b701a9 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/Handler.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/Handler.js @@ -43,6 +43,7 @@ define( this._details = new ObjectMap(); this._objectType = objectType; this._cache = new Dictionary(); + this._objects = new Dictionary(); this._popoverCurrentObjectId = 0; @@ -76,8 +77,7 @@ define( var element, elements = elBySelAll(this._options.containerSelector), elementData, triggerChange = false, objectId; for (var i = 0, length = elements.length; i < length; i++) { element = elements[i]; - objectId = ~~elData(element, 'object-id'); - if (this._containers.has(objectId)) { + if (this._containers.has(DomUtil.identify(element))) { continue; } @@ -87,9 +87,20 @@ define( element: element }; - this._containers.set(objectId, elementData); + this._containers.set(DomUtil.identify(element), elementData); this._initReactButton(element, elementData); + if (!this._objects.has(~~elData(element, 'object-id'))) { + var objects = []; + } + else { + var objects = this._objects.get(~~elData(element, 'object-id')); + } + + objects.push(elementData); + + this._objects.set(~~elData(element, 'object-id'), objects); + triggerChange = true; } @@ -174,18 +185,20 @@ define( }, _updateReactButton: function(objectID, reactionTypeID) { - if (reactionTypeID) { - this._containers.get(objectID).reactButton.classList.add('active'); - elData(this._containers.get(objectID).reactButton, 'reaction-type-id', reactionTypeID); - } - else { - elData(this._containers.get(objectID).reactButton, 'reaction-type-id', 0); - this._containers.get(objectID).reactButton.classList.remove('active'); - } + this._objects.get(objectID).forEach(function (elementData) { + if (reactionTypeID) { + elementData.reactButton.classList.add('active'); + elData(elementData.reactButton, 'reaction-type-id', reactionTypeID); + } + else { + elData(elementData.reactButton, 'reaction-type-id', 0); + elementData.reactButton.classList.remove('active'); + } + }); }, _markReactionAsActive: function() { - var reactionTypeID = elData(this._containers.get(this._popoverCurrentObjectId).reactButton, 'reaction-type-id'); + var reactionTypeID = elData(this._objects.get(this._popoverCurrentObjectId)[0].reactButton, 'reaction-type-id'); // clear old active state var elements = elBySelAll('.reactionTypeButton.active', this._getPopover()); @@ -235,7 +248,7 @@ define( _openReactPopover: function(objectId, element) { // first close old popover, if exists if (this._popoverCurrentObjectId !== 0) { - this._closePopover(this._popoverCurrentObjectId, this._containers.get(this._popoverCurrentObjectId).reactButton); + this._closePopover(); } this._popoverCurrentObjectId = objectId; @@ -344,9 +357,9 @@ define( this._getPopover().classList.remove('active'); if (this._options.isButtonGroupNavigation) { - // find nav element - var nav = this._containers.get(this._popoverCurrentObjectId).reactButton.closest('nav'); - nav.style.cssText = ""; + this._objects.get(this._popoverCurrentObjectId).forEach(function (elementData) { + elementData.reactButton.closest('nav').style.cssText = ""; + }); } this._popoverCurrentObjectId = 0; @@ -368,7 +381,7 @@ define( parameters: this._options.parameters }); - this._closePopover(this._popoverCurrentObjectId, this._containers.get(this._popoverCurrentObjectId).reactButton); + this._closePopover(); }, _ajaxSuccess: function(data) { -- 2.20.1