From 4da5c47356f1e5635d1b113e5400b324ec7795bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?"J.=20Rene=CC=81e=20Beach"?= <splendidnoise@gmail.com>
Date: Tue, 5 Mar 2013 02:12:59 -0500
Subject: [PATCH] Issue #1847084 by LewisNyman, tarekdj, trawekp, jessebeach:
 Vertical toolbar doesn't work with overlay
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: J. Renée Beach <splendidnoise@gmail.com>
---
 core/misc/displace.js                     |  100 +++++++++++++++++++++++++++++
 core/modules/overlay/overlay-parent.js    |   27 +++++---
 core/modules/overlay/overlay.module       |    1 +
 core/modules/system/system.module         |   15 +++++
 core/modules/toolbar/css/toolbar.base.css |    2 +-
 core/modules/toolbar/js/toolbar.js        |   15 ++++-
 core/modules/toolbar/toolbar.module       |    5 +-
 7 files changed, 152 insertions(+), 13 deletions(-)
 create mode 100644 core/misc/displace.js

diff --git a/core/misc/displace.js b/core/misc/displace.js
new file mode 100644
index 0000000..066f0b8
--- /dev/null
+++ b/core/misc/displace.js
@@ -0,0 +1,100 @@
+/**
+ *
+ */
+(function (window, Drupal, $) {
+  var offsets = {
+    top: 0,
+    right: 0,
+    bottom: 0,
+    left: 0
+  };
+
+  var displacingElements = {
+    top: [],
+    right: [],
+    bottom: [],
+    left: []
+  }
+  var displacingDimension = {
+    top: 'height',
+    right: 'width',
+    bottom: 'height',
+    left: 'width'
+  }
+
+  /**
+   * Registers a resize hanlder on the window.
+   */
+  Drupal.behaviors.drupalDisplace = {
+    attach: function (context, settings) {
+      $('body').once('drupalDisplace', function (index, element) {
+        findDisplacingElements();
+        $(window).on('resize.drupalDisplace', displace);
+      });
+    }
+  };
+
+  /**
+   * Finds and stores elements with a .data-offset-{edge} class.
+   */
+  function findDisplacingElements () {
+    // Find the displacing elements.
+    for (var edge in displacingElements) {
+      if (displacingElements.hasOwnProperty(edge)) {
+        displacingElements[edge] = $('[data-offset-' + edge + ']');
+      }
+    }
+  }
+
+  /**
+   * Determines the viewport offsets.
+   */
+  function calculateOffsets () {
+    // Go through each edge and add up the displacements.
+    for (var edge in displacingElements) {
+      var displacement = 0;
+      if (displacingElements.hasOwnProperty(edge)) {
+        for (var i = 0; i < displacingElements[edge].length; i++) {
+          var $el = displacingElements[edge].eq(i);
+          // If the offset data attribute contains a displacing value, use it.
+          var value = parseInt($el.attr('data-offset-' + edge), 10);
+          if (typeof value === 'number') {
+            displacement += value;
+          }
+          // If the element's offset data attribute does not contain a value,
+          // try to get the displacing dimension from the element directly.
+          else {
+            displacement += $el[displacingDimension[edge]]();
+          }
+        }
+        // Store the displacement vlaue in the closure's offset variable.
+        offsets[edge] = displacement;
+      }
+    }
+  }
+
+  /**
+   * Informs listeners of the current offset dimensions.
+   */
+  function displace() {
+    findDisplacingElements();
+    calculateOffsets();
+    $(document).trigger('drupalViewportOffsetChange', offsets);
+  }
+
+  /**
+   * Returns the current offset dimensions.
+   */
+  displace.getOffsets = function (refresh) {
+      if (refresh) {
+        calculateOffsets();
+      }
+      return offsets;
+  };
+
+  /**
+   * API
+   */
+  Drupal.displace = displace;
+
+}(window, Drupal, jQuery));
diff --git a/core/modules/overlay/overlay-parent.js b/core/modules/overlay/overlay-parent.js
index caf9336..390ebd6 100644
--- a/core/modules/overlay/overlay-parent.js
+++ b/core/modules/overlay/overlay-parent.js
@@ -34,6 +34,10 @@ Drupal.behaviors.overlayParent = {
       return;
     }
 
+    // The overlay's positioning can be affected by other elements on the page.
+    // Get the current viewpor offset values.
+    Drupal.overlay.viewportOffsets = Drupal.displace.getOffsets(true);
+
     $(document)
       // Instead of binding a click event handler to every link we bind one to
       // the document and only handle events that bubble up. This allows other
@@ -131,6 +135,7 @@ Drupal.overlay.create = function () {
   $(window)
     .bind('resize' + eventClass, $.proxy(this, 'eventhandlerOuterResize'));
   $(document)
+    .on('drupalViewportOffsetChange' + eventClass, $.proxy(this, 'eventhandlerViewportOffsetChange'))
     .bind('drupalOverlayLoad' + eventClass, $.proxy(this, 'eventhandlerOuterResize'))
     .bind('drupalOverlayReady' + eventClass +
           ' drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerSyncURLFragment'))
@@ -398,6 +403,14 @@ Drupal.overlay.isExternalLink = function (url) {
 };
 
 /**
+ *
+ */
+Drupal.overlay.eventhandlerViewportOffsetChange = function (event, offsets) {
+  Drupal.overlay.viewportOffsets = offsets;
+  Drupal.overlay.eventhandlerOuterResize();
+}
+
+/**
  * Event handler: resizes overlay according to the size of the parent window.
  *
  * @param event
@@ -435,15 +448,13 @@ Drupal.overlay.eventhandlerAlterDisplacedElements = function (event) {
     return;
   }
 
+  var offsets = Drupal.overlay.viewportOffsets;
+
   $(this.iframeWindow.document.body).css({
-    marginTop: Drupal.overlay.getDisplacement('top'),
-    marginBottom: Drupal.overlay.getDisplacement('bottom')
-  }).attr('data-offset-top', Drupal.overlay.getDisplacement('top'));
-
-  $(document).bind('offsettopchange', function () {
-    var iframeDocument = Drupal.overlay.iframeWindow.document;
-    $(iframeDocument.body).attr('data-offset-top', Drupal.overlay.getDisplacement('top'));
-    $(iframeDocument).trigger('offsettopchange');
+    'margin-top': offsets.top,
+    'margin-right': offsets.right,
+    'margin-bottom': offsets.bottom,
+    'margin-left': offsets.left
   });
 
   var documentHeight = this.iframeWindow.document.body.clientHeight;
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index cc29255..197d006 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -225,6 +225,7 @@ function overlay_library_info() {
       array('system', 'jquery'),
       array('system', 'drupal'),
       array('system', 'drupalSettings'),
+      array('system', 'drupal.displace'),
       array('system', 'jquery.ui.core'),
       array('system', 'jquery.bbq'),
     ),
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 3f01968..eb17a05 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1380,6 +1380,21 @@ function system_library_info() {
     ),
   );
 
+  // A utility that measures elements like the toolbar that can potentially
+  // displace the positioning of display elements like the overlay.
+  $libraries['drupal.displace'] = array(
+    'title' => 'Drupal displace',
+    'version' => VERSION,
+    'js' => array(
+      'core/misc/displace.js' => array('group' => JS_LIBRARY),
+    ),
+    'dependencies' => array(
+      array('system', 'jquery'),
+      array('system', 'drupal'),
+      array('system', 'drupal.debounce'),
+    ),
+  );
+
   // A utility function to limit calls to a function with a given time.
   $libraries['drupal.debounce'] = array(
     'title' => 'Drupal debounce',
diff --git a/core/modules/toolbar/css/toolbar.base.css b/core/modules/toolbar/css/toolbar.base.css
index 58a2c2b..64e6468 100644
--- a/core/modules/toolbar/css/toolbar.base.css
+++ b/core/modules/toolbar/css/toolbar.base.css
@@ -91,7 +91,7 @@ html.js .toolbar {
   position: absolute;
 }
 .toolbar .tray {
-  z-index: 250;
+  z-index: 1200;
 }
 .toolbar .horizontal {
   width: 100%;
diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js
index 45e91ad..dc476ce 100644
--- a/core/modules/toolbar/js/toolbar.js
+++ b/core/modules/toolbar/js/toolbar.js
@@ -192,8 +192,17 @@ Drupal.toolbar.setHeight = function () {
     $toolbar.attr('data-offset-top', height);
     // Alter the padding on the top of the body element.
     $('body').css('padding-top', height);
-    $(document).trigger('offsettopchange', height);
-    $(window).trigger('resize');
+    Drupal.displace();
+  }
+};
+
+Drupal.toolbar.setTrayWidth = function () {
+  var $tray = $toolbar.find('.tray.active.vertical');
+  var trayWidth = $tray.width();
+  var offset = parseInt($tray.attr('data-offset-left'), 10);
+  if (offset !== trayWidth) {
+    $tray.attr('data-offset-left', trayWidth);
+    Drupal.displace();
   }
 };
 
@@ -296,6 +305,8 @@ function updatePeripherals () {
   setBodyState();
   // Adjust the height of the toolbar.
   Drupal.toolbar.setHeight();
+  // Adjust the tray width for vertical trays.
+  Drupal.toolbar.setTrayWidth();
 }
 
 /**
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index e4996bc..3292242 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -93,7 +93,7 @@ function toolbar_element_info() {
       'id' => 'toolbar-administration',
       // The 'overlay-displace-top' class pushes the overlay down, so it appears
       // below the toolbar.
-      'class' => array('toolbar', 'overlay-displace-top'),
+      'class' => array('toolbar',),
       'role' => 'navigation',
     ),
     // Metadata for the administration bar.
@@ -101,7 +101,7 @@ function toolbar_element_info() {
       '#heading' => t('Toolbar items'),
       '#attributes' => array(
         'id' => 'toolbar-bar',
-        'class' => array('bar', 'overlay-displace-top', 'clearfix'),
+        'class' => array('bar', 'clearfix'),
       ),
     ),
   );
@@ -631,6 +631,7 @@ function toolbar_library_info() {
       array('system', 'matchmedia'),
       array('system', 'jquery.once'),
       array('system', 'drupal.debounce'),
+      array('system', 'drupal.displace'),
       array('toolbar', 'toolbar.menu'),
     ),
   );
-- 
1.7.10.4

