From 6eb83a3d0033d87f4b2ed8e81382f39b23896b51 Mon Sep 17 00:00:00 2001
From: Robin Ward <robin.ward@gmail.com>
Date: Mon, 9 Nov 2015 13:25:50 -0500
Subject: [PATCH] FIX: Tweak the mutationObserver to respect attributes.

To avoid crashing Firefox, it checks that the values actually changed.
This eliminates a bug where whitespace sometimes appeared in an
expanded menu.
---
 .../discourse/components/menu-panel.js.es6    | 24 ++++++++++++++-----
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/app/assets/javascripts/discourse/components/menu-panel.js.es6 b/app/assets/javascripts/discourse/components/menu-panel.js.es6
index 5fb1e034ab9..d0dfee59702 100644
--- a/app/assets/javascripts/discourse/components/menu-panel.js.es6
+++ b/app/assets/javascripts/discourse/components/menu-panel.js.es6
@@ -24,13 +24,19 @@ export default Ember.Component.extend({
     const $panelBody = this.$('.panel-body');
     let contentHeight = parseInt(this.$('.panel-body-contents').height());
 
+    // We use a mutationObserver to check for style changes, so it's important
+    // we don't set it if it doesn't change. Same goes for the $panelBody!
+    const style = this.$().prop('style');
+
     if (viewMode === 'drop-down') {
       const $buttonPanel = $('header ul.icons');
       if ($buttonPanel.length === 0) { return; }
 
       // These values need to be set here, not in the css file - this is to deal with the
       // possibility of the window being resized and the menu changing from .slide-in to .drop-down.
-      this.$().css({ top: '100%', height: 'auto' });
+      if (style.top !== '100%' || style.height !== 'auto') {
+        this.$().css({ top: '100%', height: 'auto' });
+      }
 
       // adjust panel height
       const fullHeight = parseInt($window.height());
@@ -40,7 +46,9 @@ export default Ember.Component.extend({
       if (contentHeight + (offsetTop - scrollTop) + PANEL_BODY_MARGIN > fullHeight) {
         contentHeight = fullHeight - (offsetTop - scrollTop) - PANEL_BODY_MARGIN;
       }
-      $panelBody.height(contentHeight);
+      if ($panelBody.height() !== contentHeight) {
+        $panelBody.height(contentHeight);
+      }
       $('body').addClass('drop-down-visible');
     } else {
       const menuTop = headerHeight();
@@ -53,8 +61,12 @@ export default Ember.Component.extend({
         height = winHeight - menuTop;
       }
 
-      $panelBody.height('100%');
-      this.$().css({ top: menuTop + "px", height });
+      if ($panelBody.prop('style').height !== '100%') {
+        $panelBody.height('100%');
+      }
+      if (style.top !== menuTop + "px" || style.height !== height) {
+        this.$().css({ top: menuTop + "px", height });
+      }
       $('body').removeClass('drop-down-visible');
     }
 
@@ -127,7 +139,7 @@ export default Ember.Component.extend({
   _watchSizeChanges() {
     if (mutationSupport) {
       this._observer.disconnect();
-      this._observer.observe(this.element, { childList: true, subtree: true });
+      this._observer.observe(this.element, { childList: true, subtree: true, characterData: true, attributes: true });
     } else {
       clearInterval(this._resizeInterval);
       this._resizeInterval = setInterval(() => {
@@ -176,7 +188,7 @@ export default Ember.Component.extend({
 
     if (mutationSupport) {
       this._observer = new MutationObserver(() => {
-        Ember.run(() => this.performLayout());
+        Ember.run.debounce(this, this.performLayout, 50);
       });
     }