diff --git a/core/misc/displace.js b/core/misc/displace.js index 56f2327..72a081c 100644 --- a/core/misc/displace.js +++ b/core/misc/displace.js @@ -2,6 +2,7 @@ * */ (function (window, Drupal, $) { + var offsets = { top: 0, right: 0, @@ -15,6 +16,7 @@ bottom: [], left: [] } + var displacingDimension = { top: 'height', right: 'width', @@ -23,42 +25,64 @@ } /** - * Registers a resize hanlder on the window. + * Informs listeners of the current offset dimensions. */ - Drupal.behaviors.drupalDisplace = { - attach: function (context, settings) { - // once() returns a jQuery set. It will be empty if no unprocessed - // elements are found. window and window.parent are equivalent unless the - // Drupal page is itself wrapped in an iframe. - $(window.parent.document.body).once('drupalDisplace', function () { - // If this window is itself in an iframe it must be marked as processed. - // Its parent window will have been processed above. - // When attach() is called again for the preview iframe, it will check - // its parent window and find it has been processed. In most cases, the - // following code will have no effect. - $(window.document.body).once('drupalDisplace'); + function displace() { + calculateOffsets(); + $(document).trigger('drupalViewportOffsetChange', offsets); + } - findDisplacingElements(); - // Displace attaches a drupalOffsetChange handler to the parent body - // the handler is wrapped with debounce - // in case of offsets changed on every resize - $(window.parent.document.body).on('drupalOffsetChange.drupalDisplace', - Drupal.debounce(displace, 200)); - }); + /** + * Returns the current offset dimensions. + */ + displace.getOffsets = function (refresh) { + if (refresh) { + calculateOffsets(); } + return offsets; }; /** - * Finds and stores elements with a .data-offset-{edge} class. + * Registers elements that should be used to determine viewport offset sizes. */ - function findDisplacingElements () { - // Find the displacing elements. - for (var edge in displacingElements) { - if (displacingElements.hasOwnProperty(edge)) { - displacingElements[edge] = $('[data-offset-' + edge + ']:visible'); + displace.registerElements = function (elementsByEdge) { + // Go through each edge in elementsByEdge. + for (var edge in elementsByEdge) { + if (elementsByEdge.hasOwnProperty(edge)) { + // Each element or set of elements must be listed under an edge + // property. + if ($.inArray(edge, ['top', 'right', 'bottom', 'left']) === -1) { + continue; + } + var elements = elementsByEdge[edge]; + // Wrap the elements in an array if just one element is provided. + elements = (!'length' in elements) ? [elements] : elements; + // Loop through each element and add it to the list of displacing + // elements for the given edge. + for (var i = 0, n = elements.length; i < n; i++) { + // The elements will be stored as DOM nodes for consistency. + var el = ('get' in elements[i]) ? elements[i].get() : elements[i]; + displacingElements[edge].push(el); + } + // Sort the displacing elements for the edge and remove duplicates. + displacingElements[edge] = $.unique(displacingElements[edge]); } } - } + }; + + /** + * Removes elements from the list of displacing elements for an edge. + */ + displace.removeElements = function (elementsByEdge) { + // @todo provide a way to remove elements from the set of displacing elements. + }; + + /** + * Returns the object that lists the displacing elements by edge. + */ + displace.getElements = function () { + return displacingElements; + }; /** * Determines the viewport offsets. @@ -66,49 +90,35 @@ 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]](); + var displacement = 0; + if (displacingElements.hasOwnProperty(edge)) { + for (var i = 0, n = displacingElements[edge].length; i < n; i++) { + var $el = $(displacingElements[edge][i]); + // If the element is not visble, do not use its dimensions. + if (!$el.is(':visible')) { + continue; + } + // 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 offsets variable. + offsets[edge] = displacement; } - // 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) { - findDisplacingElements(); - calculateOffsets(); - } - return offsets; - }; - - /** - * API + * Assign the displace function to a property of the Drupal global object. */ Drupal.displace = displace; diff --git a/core/modules/overlay/overlay-child.css b/core/modules/overlay/overlay-child.css index aff4203..66f07bc 100644 --- a/core/modules/overlay/overlay-child.css +++ b/core/modules/overlay/overlay-child.css @@ -16,6 +16,7 @@ } #overlay { + box-sizing: border-box; display: block; margin: 0 auto; max-width: 80em; @@ -25,6 +26,7 @@ padding-bottom: 2em; padding-left: 40px; padding-right: 40px; + width: 100%; } #overlay-titlebar { padding: 0 20px; diff --git a/core/modules/overlay/overlay-parent.js b/core/modules/overlay/overlay-parent.js index 5d1088b..fbe1e7f 100644 --- a/core/modules/overlay/overlay-parent.js +++ b/core/modules/overlay/overlay-parent.js @@ -144,7 +144,7 @@ Drupal.overlay.create = function () { ' drupalOverlayBeforeLoad' + eventClass + ' drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerDispatchEvent')); - if ($('.overlay-displace-top, .overlay-displace-bottom').length) { + if (Drupal.displace.getElements().top.length || Drupal.displace.getElements().bottom.length) { $(document) .bind('drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerAlterDisplacedElements')) .bind('drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerRestoreDisplacedElements')); diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js index 57edd29..267f1b6 100644 --- a/core/modules/toolbar/js/toolbar.js +++ b/core/modules/toolbar/js/toolbar.js @@ -84,6 +84,12 @@ Drupal.behaviors.toolbar = { // Call setHeight on screen resize. Wrap it in debounce to prevent // setHeight from being called too frequently. var setHeight = Drupal.debounce(Drupal.toolbar.setHeight, 200); + // Register elements with Drupal.displace that could affect the size and + // placement of other UI components. + Drupal.displace.registerElements({ + top: $toolbar, + left: $trays + }); // Attach behavior to the window. $(window) .on('resize.toolbar', setHeight); @@ -192,7 +198,8 @@ 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); - $toolbar.trigger('drupalOffsetChange'); + // Trigger a recalculation of viewport displacing elements. + Drupal.displace(); } }; @@ -202,7 +209,8 @@ Drupal.toolbar.setTrayWidth = function () { var offset = $tray.attr('data-offset-left'); if (offset !== trayWidth) { $tray.attr('data-offset-left', trayWidth); - $tray.trigger('drupalOffsetChange'); + // Trigger a recalculation of viewport displacing elements. + Drupal.displace(); } }; diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module index 3292242..5cd1f5b 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -315,7 +315,6 @@ function toolbar_pre_render_item($element) { } $element['tray']['#wrapper_attributes'] += $attributes; $element['tray']['#wrapper_attributes']['class'][] = 'tray'; - $element['tray']['#wrapper_attributes']['class'][] = 'overlay-displace-top'; if (!isset($element['tray']['#theme_wrappers'])) { $element['tray']['#theme_wrappers'] = array();