Bug 1204101 - Fix for Loop settings menu positioning where menu gets cropped from longer text, r=dmose,a=lhenry
authorDavid Critchley <david@priologic.com>
Tue, 29 Sep 2015 13:08:22 -0700
changeset 296256 587400bad501daf5531e25bfb52496430c1e713d
parent 296255 32551122be1c6499c1b4a8a2542e3f4e41da7967
child 296257 29676f10e50295dd3b706ed782673fd4c5a66077
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdmose, lhenry
bugs1204101
milestone43.0a2
Bug 1204101 - Fix for Loop settings menu positioning where menu gets cropped from longer text, r=dmose,a=lhenry
browser/components/loop/content/shared/js/mixins.js
browser/components/loop/content/shared/js/views.js
browser/components/loop/content/shared/js/views.jsx
--- a/browser/components/loop/content/shared/js/mixins.js
+++ b/browser/components/loop/content/shared/js/mixins.js
@@ -1,11 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
+// This mixin should be deprecated and a new solution implemented for
+// processing menus and taking care of menu positioning globally. This
+// new implementation should ensure all menus are positioned using the
+// same method of positioning
 
 var loop = loop || {};
 loop.shared = loop.shared || {};
 loop.shared.mixins = (function() {
   "use strict";
 
   /**
    * Root object, by default set to window.
@@ -223,16 +227,21 @@ loop.shared.mixins = (function() {
             // amount.
             y += menuNodeRect.height - (boundingRect.height + y);
           }
           menu.style.marginTop =  y + "px";
         } else if (!menu.style.marginLeft) {
           menu.style.marginTop = "auto";
         }
 
+        // Added call to _repositionMenu() if it exists, to allow a component to
+        // add specific repositioning to a menu.
+        if (this._repositionMenu) {
+          this._repositionMenu();
+        }
         menu.style.visibility = "visible";
       },
 
       componentDidMount: function() {
         this.documentBody.addEventListener("click", this._onBodyClick);
         rootObject.addEventListener("blur", this.hideDropdownMenu);
       },
 
--- a/browser/components/loop/content/shared/js/views.js
+++ b/browser/components/loop/content/shared/js/views.js
@@ -198,21 +198,58 @@ loop.shared.views = (function(_, mozL10n
 
     getDefaultProps: function() {
       return {
         menuBelow: false
       };
     },
 
     /**
-     * Show or hide the settings menu
+     * Reposition Menu if cropped
+     *
+     * Added to reposition the menu if it is cropped on the left side because of
+     * a long text string. This function measures how much the menu is cropped
+     * on the left or right and adjusts the coordinates so the menu isn't cropped.
+     * Also, sets the left style to auto, to prevent complexity in calculations
+     *
+     * The dropdownmenu mixin needs to be revamped, along with all components
+     * using dropdown menus. Components should be utilizing a global function
+     * for menu positions and it should be consistent throughout.
+     *
      */
-    handleClick: function(event) {
-      event.preventDefault();
-      this.toggleDropdownMenu();
+    _repositionMenu: function() {
+      if (this.refs.menu && this.state.showMenu) {
+        var menuNode = this.refs.menu && this.refs.menu.getDOMNode();
+
+        if (menuNode) {
+          // Amount of pixels that the dropdown needs to stay away from the edges
+          // of the page body. Copied from the mixin.
+          var boundOffset = 4;
+          var menuNodeRect = menuNode.getBoundingClientRect();
+          var menuComputedStyle = window.getComputedStyle(menuNode);
+          var documentBody = this.getDOMNode().ownerDocument.body;
+          var bodyRect = documentBody.getBoundingClientRect();
+          var menuLeft = parseFloat(menuNodeRect.left);
+          var menuRight = parseFloat(menuNodeRect.right);
+          var bodyRight = parseFloat(bodyRect.right);
+
+          menuNode.style.left = "auto";
+
+          // If menu is too close or cropped on left, move right
+          if (menuLeft < -boundOffset) {
+            menuNode.style.right =
+              (parseFloat(menuComputedStyle.right) + menuLeft - boundOffset) + "px";
+          }
+          // If menu is too close or cropped on right, move left
+          if (menuRight > bodyRight - boundOffset) {
+            menuNode.style.right =
+              (parseFloat(menuComputedStyle.right) + (menuRight - bodyRight) + boundOffset) + "px";
+          }
+        }
+      }
     },
 
     /**
      * Return the function that Show or hide the edit context edition form
      */
     getHandleToggleEdit: function(editItem) {
       return function _handleToglleEdit(event) {
           event.preventDefault();
--- a/browser/components/loop/content/shared/js/views.jsx
+++ b/browser/components/loop/content/shared/js/views.jsx
@@ -198,21 +198,58 @@ loop.shared.views = (function(_, mozL10n
 
     getDefaultProps: function() {
       return {
         menuBelow: false
       };
     },
 
     /**
-     * Show or hide the settings menu
+     * Reposition Menu if cropped
+     *
+     * Added to reposition the menu if it is cropped on the left side because of
+     * a long text string. This function measures how much the menu is cropped
+     * on the left or right and adjusts the coordinates so the menu isn't cropped.
+     * Also, sets the left style to auto, to prevent complexity in calculations
+     *
+     * The dropdownmenu mixin needs to be revamped, along with all components
+     * using dropdown menus. Components should be utilizing a global function
+     * for menu positions and it should be consistent throughout.
+     *
      */
-    handleClick: function(event) {
-      event.preventDefault();
-      this.toggleDropdownMenu();
+    _repositionMenu: function() {
+      if (this.refs.menu && this.state.showMenu) {
+        var menuNode = this.refs.menu && this.refs.menu.getDOMNode();
+
+        if (menuNode) {
+          // Amount of pixels that the dropdown needs to stay away from the edges
+          // of the page body. Copied from the mixin.
+          var boundOffset = 4;
+          var menuNodeRect = menuNode.getBoundingClientRect();
+          var menuComputedStyle = window.getComputedStyle(menuNode);
+          var documentBody = this.getDOMNode().ownerDocument.body;
+          var bodyRect = documentBody.getBoundingClientRect();
+          var menuLeft = parseFloat(menuNodeRect.left);
+          var menuRight = parseFloat(menuNodeRect.right);
+          var bodyRight = parseFloat(bodyRect.right);
+
+          menuNode.style.left = "auto";
+
+          // If menu is too close or cropped on left, move right
+          if (menuLeft < -boundOffset) {
+            menuNode.style.right =
+              (parseFloat(menuComputedStyle.right) + menuLeft - boundOffset) + "px";
+          }
+          // If menu is too close or cropped on right, move left
+          if (menuRight > bodyRight - boundOffset) {
+            menuNode.style.right =
+              (parseFloat(menuComputedStyle.right) + (menuRight - bodyRight) + boundOffset) + "px";
+          }
+        }
+      }
     },
 
     /**
      * Return the function that Show or hide the edit context edition form
      */
     getHandleToggleEdit: function(editItem) {
       return function _handleToglleEdit(event) {
           event.preventDefault();