diff --git a/core/misc/displace.js b/core/misc/displace.js index 9ca72f5..f2638f5 100644 --- a/core/misc/displace.js +++ b/core/misc/displace.js @@ -10,72 +10,28 @@ left: 0 }; - var displacingElements = []; - /** * Informs listeners of the current offset dimensions. + * + * @param Boolean refresh + * - When true or undefined, causes the current offsets values to be + * recalculated. */ - function displace() { - calculateOffsets(); - $(document).trigger('drupalViewportOffsetChange', offsets); - } - - /** - * Returns the current offset dimensions. - */ - displace.getOffsets = function (refresh) { - if (refresh) { + function displace (refresh) { + if (refresh === undefined || refresh) { calculateOffsets(); + $(document).trigger('drupalViewportOffsetChange', offsets); } return offsets; - }; - - /** - * Registers elements that should be used to determine viewport offset sizes. - */ - displace.registerElements = function (elements) { - // 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 element = ('get' in elements[i]) ? elements[i].get() : elements[i]; - displacingElements.push(element); - } - - // Remove duplicates. - displacingElements = $.unique(displacingElements); - }; - - /** - * Removes elements from the list of displacing elements for an edge. - */ - displace.removeElements = function (elements) { - var remove = []; - - // Wrap the elements in an array if just one element is provided. - elements = (!'length' in elements) ? [elements] : elements; - for (var i = 0, n = elements.length; i < n; i++) { - var el = ('get' in elements[i]) ? elements[i].get() : elements[i]; - remove.push(el); - } - - // Filter displacingElements by provided elements - displacingElements = $.grep(displacingElements, function(el) { - return $.inArray(el, remove) === -1; - }); - }; - - /** - * Returns the object that lists the displacing elements by edge. - */ - displace.getElements = function () { - return displacingElements; - }; + } /** * Determines the viewport offsets. + * + * Any element with the attribute data-offset-{edge} e.g. data-offset-top will + * be consider in the viewport offset calculations. If the attribute has a + * numeric value, that value will be used. If no value is provided, one will + * be calculated using the element's dimensions and placement. */ function calculateOffsets () { // Perform the calculations on a local varialbe @@ -85,78 +41,84 @@ bottom: 0, left: 0 } - // Go through the displacing elements on each edge and calculate the - // offset. - for (var i = 0, n = displacingElements.length; i < n; i++) { - var $el = $(displacingElements[i]); - // If the element is not visble, do not use its dimensions. - if (!$el.is(':visible')) { - continue; - } - // Go through each edge and add up the displacements. - for (var edge in offset) { - if (offset.hasOwnProperty(edge)) { - var displacement = 0; - // If the offset data attribute contains a displacing value, use it. - displacement = $el.attr('data-offset-' + edge); - // If the element's offset data attribute does not exists - // then move to another edge - if (typeof displacement === 'undefined') { + // Go through each edge and find the largest displacement. + for (var edge in offset) { + if (offset.hasOwnProperty(edge)) { + var $displacingElements = $('[data-offset-' + edge + ']'); + for (var i = 0, n = $displacingElements.length; i < n; i++) { + var $el = $displacingElements.eq(i); + // If the element is not visble, do consider its dimensions. + if (!$el.is(':visible')) { continue; } - // Try to parse displacement to number - displacement = parseInt(displacement, 10); + // If the offset data attribute contains a displacing value, use it. + var displacement = parseInt($el.attr('data-offset-' + edge), 10); // If the element's offset data attribute exits // but is not a valid number then get the displacement - // dimensions directly form the element - if (typeof displacement !== 'number' || isNaN(displacement) || displacement < 0) { - var size = 0; - var docSize = 0; - // Get the offset of the element itself. - var placement = $el.offset()[(edge === 'left' || edge === 'right') ? 'left' : 'top']; - // Subtract scroll distance from placement to get the distance - // to the edge of the viewport. - placement = placement - window['scroll' + ((edge === 'right' || edge === 'left') ? 'X' : 'Y')]; - // Find the displacement value according to the edge. - switch (edge) { - // Left and top elements displace as a sum of their own offset value - // plus their size. - case 'top': - size = $el.outerHeight(); - // Total displacment is the sum of the elements placement and size. - displacement = placement + size; - break; - case 'left': - size = $el.outerWidth(); - // Total displacment is the sum of the elements placement and size. - displacement = placement + size; - break; - // Right and bottom elements displace according to their left and - // top offset. Their size isn't important. - case 'bottom': - docSize = document.documentElement.clientHeight; - displacement = docSize - placement; - break; - case 'right': - docSize = document.documentElement.clientWidth; - displacement = docSize - placement; - break; - default: - displacement = 0; - } + // dimensions directly from the element. + if (typeof displacement !== 'number' || isNaN(displacement)) { + displacement = getRawOffset($el, edge); } // If the displacement value is larger than the current value for this - // edge, use the value. + // edge, use the displacement value. offset[edge] = Math.max(offset[edge], displacement); } } } - console.log(offset); // Store the calculated offset offsets = offset; } /** + * Calculates displacement for element based on its dimensions and placement. + * + * @param jQuery $el + * - The jQuery element whose dimensions and placement will be measured. + * + * @param string edge + * - The name of the edge of the viewport that the element is associated + * with. + */ + function getRawOffset ($el, edge) { + var size = 0; + var docSize = 0; + var displacement = 0; + // Get the offset of the element itself. + var placement = $el.offset()[(edge === 'left' || edge === 'right') ? 'left' : 'top']; + // Subtract scroll distance from placement to get the distance + // to the edge of the viewport. + placement = placement - window['scroll' + ((edge === 'right' || edge === 'left') ? 'X' : 'Y')]; + // Find the displacement value according to the edge. + switch (edge) { + // Left and top elements displace as a sum of their own offset value + // plus their size. + case 'top': + size = $el.outerHeight(); + // Total displacment is the sum of the elements placement and size. + displacement = placement + size; + break; + case 'left': + size = $el.outerWidth(); + // Total displacment is the sum of the elements placement and size. + displacement = placement + size; + break; + // Right and bottom elements displace according to their left and + // top offset. Their size isn't important. + case 'bottom': + docSize = document.documentElement.clientHeight; + displacement = docSize - placement; + break; + case 'right': + docSize = document.documentElement.clientWidth; + displacement = docSize - placement; + break; + default: + displacement = 0; + } + return displacement; + } + + /** * Assign the displace function to a property of the Drupal global object. */ Drupal.displace = displace; diff --git a/core/modules/overlay/overlay-parent.js b/core/modules/overlay/overlay-parent.js index 52de4b4..0c47f2c 100644 --- a/core/modules/overlay/overlay-parent.js +++ b/core/modules/overlay/overlay-parent.js @@ -34,10 +34,6 @@ 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 @@ -110,6 +106,11 @@ Drupal.overlay.open = function (url) { * Create the underlying markup and behaviors for the overlay. */ Drupal.overlay.create = function () { + // The overlay's positioning can be affected by other elements on the page. + // Get the current viewpor offset values. + this.viewportOffsets = Drupal.displace(); + + // Build the overlay container. this.$container = $(Drupal.theme('overlayContainer')) .appendTo(document.body); @@ -491,7 +492,7 @@ Drupal.overlay.eventhandlerAlterDisplacedElements = function (event) { // Consider any element that should be visible above the overlay (such as // a toolbar). - $(Drupal.displace.getElements().top).add(Drupal.displace.getElements().bottom).each(function () { + $('[data-offset-top]').add('[data-offset-bottom]').each(function () { var data = $(this).data(); var maxWidth = documentWidth; // In IE, Shadow filter makes element to overlap the scrollbar with 1px. diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js index e4e929d..ce9970c 100644 --- a/core/modules/toolbar/js/toolbar.js +++ b/core/modules/toolbar/js/toolbar.js @@ -84,10 +84,6 @@ 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($toolbar); - Drupal.displace.registerElements($trays); // Attach behavior to the window. $(window) .on('resize.toolbar', setHeight); @@ -211,14 +207,12 @@ Drupal.toolbar.setHeight = function () { * can adjust to the placement of the tray. */ Drupal.toolbar.setTrayWidth = function () { - var $tray = $toolbar.find('.tray.active'); - var trayWidth = $tray.hasClass('vertical') ? $tray.width() : 0; - var offset = $tray.attr('data-offset-left'); - if (offset !== trayWidth) { - $tray.attr('data-offset-left', trayWidth); - // Trigger a recalculation of viewport displacing elements. - Drupal.displace(); - } + // Remove the left offset from the trays. + $toolbar.find('.tray').removeAttr('data-offset-left'); + // If an active vertical tray exists, mark it as an offset element. + $toolbar.find('.tray.vertical.active').attr('data-offset-left', ''); + // Trigger a recalculation of viewport displacing elements. + Drupal.displace(); }; /**