Fix reactions for non unique containers
authorJoshua Rüsweg <ruesweg@woltlab.com>
Mon, 27 May 2019 11:38:05 +0000 (13:38 +0200)
committerJoshua Rüsweg <ruesweg@woltlab.com>
Mon, 27 May 2019 11:38:05 +0000 (13:38 +0200)
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

wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/CountButtons.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Reaction/Handler.js

index 34b50dddce28b8aca9ae848e00d4a0aecfa442df..d2211e2283d37ffc8233929a53c6d5993ba989dd 100644 (file)
@@ -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();
index 73006a2edec842f329f6ac1599806b04babe7a0a..a9b7b701a94b80566d2ca90b722ec642ef0e1862 100644 (file)
@@ -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) {