Commit 8aedb8ba authored by Angie Byron's avatar Angie Byron
Browse files

Issue #1847084 by jessebeach, trawekp, LewisNyman, nod_, tarekdj: Fixed...

Issue #1847084 by jessebeach, trawekp, LewisNyman, nod_, tarekdj: Fixed Vertical toolbar doesn't work with overlay (measure/track displacing elements better + provide change events for them).
parent 57669aab
Loading
Loading
Loading
Loading

core/misc/displace.js

0 → 100644
+179 −0
Original line number Diff line number Diff line
/**
 * Manages elements that can offset the size of the viewport.
 */
(function ($, Drupal, debounce) {

  "use strict";

  var offsets = {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0
  };

  /**
   * Registers a resize hanlder on the window.
   */
  Drupal.behaviors.drupalDisplace = {
    attach: function () {
      // Do not process the window of the overlay.
      if (parent.Drupal.overlay && parent.Drupal.overlay.iframeWindow === window) {
        return;
      }
      // Mark this behavior as processed on the first pass.
      if (this.displaceProcessed) {
        return;
      }
      this.displaceProcessed = true;

      $(window).on('resize.drupalDisplace', debounce(displace, 200));
    }
  };

  /**
   * Informs listeners of the current offset dimensions.
   *
   * @param {boolean} broadcast
   *   (optional) When true or undefined, causes the recalculated offsets values to be
   *   broadcast to listeners.
   *
   * @return {object}
   *   An object whose keys are the for sides an element -- top, right, bottom
   *   and left. The value of each key is the viewport displacement distance for
   *   that edge.
   */
  function displace (broadcast) {
    offsets = Drupal.displace.offsets = calculateOffsets();
    if (typeof broadcast === 'undefined' || broadcast) {
      $(document).trigger('drupalViewportOffsetChange', offsets);
    }
    return offsets;
  }

  /**
   * Determines the viewport offsets.
   *
   * @return {object}
   *   An object whose keys are the for sides an element -- top, right, bottom
   *   and left. The value of each key is the viewport displacement distance for
   *   that edge.
   */
  function calculateOffsets () {
    return {
      top: calculateOffset('top'),
      right: calculateOffset('right'),
      bottom: calculateOffset('bottom'),
      left: calculateOffset('left')
    };
  }

  /**
   * Gets a specific edge's offset.
   *
   * Any element with the attribute data-offset-{edge} e.g. data-offset-top will
   * be considered 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.
   *
   * @param {string} edge
   *   The name of the edge to calculate. Can be 'top', 'right',
   *   'bottom' or 'left'.
   *
   * @return {number}
   *   The viewport displacement distance for the requested edge.
   */
  function calculateOffset (edge) {
    var edgeOffset = 0;
    var displacingElements = document.querySelectorAll('[data-offset-' + edge + ']');
    for (var i = 0, n = displacingElements.length; i < n; i++) {
      var el = displacingElements[i];
      // If the element is not visble, do consider its dimensions.
      if (el.style.display === 'none') {
        continue;
      }
      // If the offset data attribute contains a displacing value, use it.
      var displacement = parseInt(el.getAttribute('data-offset-' + edge), 10);
      // If the element's offset data attribute exits
      // but is not a valid number then get the displacement
      // dimensions directly from the element.
      if (isNaN(displacement)) {
          displacement = getRawOffset(el, edge);
      }
      // If the displacement value is larger than the current value for this
      // edge, use the displacement value.
      edgeOffset = Math.max(edgeOffset, displacement);
    }

    return edgeOffset;
  }

  /**
   * 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.
   *
   * @return {number}
   *   The viewport displacement distance for the requested edge.
   */
  function getRawOffset (el, edge) {
    var $el = $(el);
    var documentElement = document.documentElement;
    var displacement = 0;
    var horizontal = (edge === 'left' || edge === 'right');
    // Get the offset of the element itself.
    var placement = $el.offset()[ horizontal ? 'left' : 'top'];
    // Subtract scroll distance from placement to get the distance
    // to the edge of the viewport.
    placement -= window['scroll' + (horizontal ? 'X' : 'Y')] || document.documentElement['scroll' + (horizontal) ? 'Left' : 'Top'] || 0;
    // 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':
        // Total displacment is the sum of the elements placement and size.
        displacement = placement + $el.outerHeight();
        break;

      case 'left':
        // Total displacment is the sum of the elements placement and size.
        displacement = placement + $el.outerWidth();
        break;

      // Right and bottom elements displace according to their left and
      // top offset. Their size isn't important.
      case 'bottom':
        displacement = documentElement.clientHeight - placement;
        break;

      case 'right':
        displacement = documentElement.clientWidth - placement;
        break;

      default:
        displacement = 0;
    }
    return displacement;
  }

  /**
   * Assign the displace function to a property of the Drupal global object.
   */
  Drupal.displace = displace;
  $.extend(Drupal.displace, {
    /**
     * Expose offsets to other scripts to avoid having to recalculate offsets
     */
    offsets: offsets,
    /**
     * Expose method to compute a single edge offsets.
     */
    calculateOffset: calculateOffset
  });

})(jQuery, Drupal, Drupal.debounce);
+11 −37
Original line number Diff line number Diff line
(function ($, Drupal) {
(function ($, Drupal, displace) {

"use strict";

@@ -39,16 +39,14 @@ function tableHeaderOnScrollHandler(e) {
  forTables('onScroll');
}

function tableHeaderOffsetChangeHandler(e) {
  // Compute the new offset value.
  TableHeader.computeOffsetTop();
  forTables('stickyPosition', TableHeader.offsetTop);
function tableHeaderOffsetChangeHandler(e, offsets) {
  forTables('stickyPosition', offsets.top);
}

// Bind event that need to change all tables.
$(window).on({
  /**
   * When resizing table width and offset top can change, recalculate everything.
   * When resizing table width can change, recalculate everything.
   */
  'resize.TableHeader': tableHeaderResizeHandler,

@@ -66,9 +64,9 @@ $(document).on({
  'columnschange.TableHeader': tableHeaderResizeHandler,

  /**
   * Offset value vas changed by a third party script.
   * Recalculate TableHeader.topOffset when viewport is resized
   */
  'offsettopchange.TableHeader': tableHeaderOffsetChangeHandler
  'drupalViewportOffsetChange.TableHeader': tableHeaderOffsetChangeHandler
});

/**
@@ -77,9 +75,6 @@ $(document).on({
 * TableHeader will make the current table header stick to the top of the page
 * if the table is very long.
 *
 * Fire a custom "topoffsetchange" event to make TableHeader compute the
 * new offset value from the "data-offset-top" attributes of relevant elements.
 *
 * @param table
 *   DOM object for the table to add a sticky header to.
 *
@@ -119,28 +114,7 @@ $.extend(TableHeader, {
   *
   * @type {Array}
   */
  tables: [],

  /**
   * Cache of computed offset value.
   *
   * @type {Number}
   */
  offsetTop: 0,

  /**
   * Sum all [data-offset-top] values and cache it.
   */
  computeOffsetTop: function () {
    var $offsets = $('[data-offset-top]');
    var value, sum = 0;
    for (var i = 0, il = $offsets.length; i < il; i++) {
      value = parseInt($offsets[i].getAttribute('data-offset-top'), 10);
      sum += !isNaN(value) ? value : 0;
    }
    this.offsetTop = sum;
    return sum;
  }
  tables: []
});

/**
@@ -211,7 +185,7 @@ $.extend(TableHeader.prototype, {
   */
  checkStickyVisible: function () {
    var scrollTop = scrollValue('scrollTop');
    var tableTop = this.tableOffset.top - TableHeader.offsetTop;
    var tableTop = this.tableOffset.top - displace.offsets.top;
    var tableBottom = tableTop + this.tableHeight;
    var visible = false;

@@ -248,9 +222,9 @@ $.extend(TableHeader.prototype, {
    this.tableHeight = this.$originalTable[0].clientHeight;

    // Update offset top.
    TableHeader.computeOffsetTop();
    displace.offsets.top = displace.calculateOffset('top');
    this.tableOffset = this.$originalTable.offset();
    this.stickyPosition(TableHeader.offsetTop);
    this.stickyPosition(displace.offsets.top, scrollValue('scrollLeft'));

    // Update columns width.
    var $that = null;
@@ -277,4 +251,4 @@ $.extend(TableHeader.prototype, {
// Expose constructor in the public space.
Drupal.TableHeader = TableHeader;

}(jQuery, Drupal));
}(jQuery, Drupal, window.parent.Drupal.displace));
+1 −15
Original line number Diff line number Diff line

/**
 * @file
 * RTL styling for Overlay child pages.
@@ -12,26 +11,13 @@ html {
  float: right;
  left: auto;
}
#overlay {
  padding: 0.2em;
  padding-left: 26px;
}
#overlay-close-wrapper {
  left: 0;
  right: auto;
}
#overlay-close,
#overlay-close:hover {
  background: transparent url(images/close.png) no-repeat;
  border-top-right-radius: 0;

  -webkit-border-top-left-radius: 12px;
  -webkit-border-bottom-left-radius: 12px;
  -moz-border-radius-topleft: 12px;
  -moz-border-radius-bottomleft: 12px;
  border-top-left-radius: 12px;
  border-bottom-left-radius: 12px;
  background-color: #ffffff;
  border-radius: 12px 0 0 12px;
}

/**
+8 −17
Original line number Diff line number Diff line

/**
 * @file
 * Basic styling for the Overlay child pages.
@@ -16,15 +15,15 @@
}

#overlay {
  display: table;
  box-sizing: border-box;
  display: block;
  margin: 0 auto;
  max-width: 80em;
  max-width: 80rem;
  min-height: 100px;
  min-width: 700px;
  position: relative;
  padding: .2em;
  padding-bottom: 2em;
  padding-right: 26px; /* LTR */
  width: 88%;
  padding: 2em 40px;
  width: 100%;
}
#overlay-titlebar {
  padding: 0 20px;
@@ -68,8 +67,8 @@
}
#overlay-close,
#overlay-close:hover {
  background: transparent url(images/close.png) no-repeat; /* LTR */
  border-top-left-radius: 0; /* LTR */
  background: #ffffff url(images/close.png) no-repeat;
  border-radius: 0 12px 12px 0; /* LTR */
  display: block;
  height: 26px;
  margin: 0;
@@ -77,14 +76,6 @@
  /* Replace with position:fixed to get a scrolling close button. */
  position: absolute;
  width: 26px;

  -webkit-border-top-right-radius: 12px;
  -webkit-border-bottom-right-radius: 12px;
  -moz-border-radius-topright: 12px;
  -moz-border-radius-bottomright: 12px;
  border-top-right-radius: 12px;
  border-bottom-right-radius: 12px;
  background-color: #ffffff;
}

/**
+8 −6
Original line number Diff line number Diff line
@@ -179,11 +179,13 @@ Drupal.overlayChild.behaviors.shortcutAddLink = function (context, settings) {
  });
};

Drupal.overlayChild.behaviors.bindDrupalViewportOffsetChangeEvent = function (context, settings) {
  // Workaround because of the way jQuery events works.
  // jQuery from the parent frame needs to be used to catch this event.
parent.jQuery(document).bind('offsettopchange', function () {
  parent.jQuery(parent.document).on('drupalViewportOffsetChange', function (event, offsets) {
    // Fires an event that the child iframe can listen to.
  $(document).trigger('offsettopchange');
    $(document).trigger('drupalViewportOffsetChange', offsets);
  });
};

})(jQuery);
Loading