From 36db8d9cdbd92b823ec1c561e631f72299c025cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?"J.=20Rene=CC=81e=20Beach"?= Date: Tue, 19 Mar 2013 14:16:00 -0400 Subject: [PATCH] Spark version of 1847084-54 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: J. ReneĢe Beach --- core/misc/displace.js | 125 +++++++++++++++++++++++++++++ core/misc/tableheader.js | 50 +++++------- core/modules/overlay/overlay-child.css | 9 ++- core/modules/overlay/overlay-child.js | 11 +-- core/modules/overlay/overlay-parent.js | 45 +++++++---- core/modules/overlay/overlay.module | 1 + core/modules/system/system.module | 16 ++++ core/modules/toolbar/css/toolbar.base.css | 2 +- core/modules/toolbar/js/toolbar.js | 36 ++++++++- core/modules/toolbar/toolbar.module | 6 +- core/themes/bartik/css/style.css | 4 +- core/themes/seven/style.css | 4 +- 12 files changed, 241 insertions(+), 68 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..3f96645 --- /dev/null +++ b/core/misc/displace.js @@ -0,0 +1,125 @@ +/** + * Manages elements that can offset the size of the viewport. + */ +(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' + } + + /** + * Informs listeners of the current offset dimensions. + */ + function displace() { + calculateOffsets(); + $(document).trigger('drupalViewportOffsetChange', offsets); + } + + /** + * Returns the current offset dimensions. + */ + displace.getOffsets = function (refresh) { + if (refresh) { + calculateOffsets(); + } + return offsets; + }; + + /** + * Registers elements that should be used to determine viewport offset sizes. + */ + 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. + */ + function calculateOffsets () { + // Go through each edge and add up the displacements. + for (var edge in displacingElements) { + if (displacingElements.hasOwnProperty(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' && !isNaN(value)) { + 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; + } + } + } + } + + /** + * Assign the displace function to a property of the Drupal global object. + */ + Drupal.displace = displace; + +}(window, Drupal, jQuery)); diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js index 0d4f7cd..633dc6e 100644 --- a/core/misc/tableheader.js +++ b/core/misc/tableheader.js @@ -1,4 +1,4 @@ -(function ($, Drupal) { +(function ($, Drupal, window, document) { "use strict"; @@ -17,10 +17,13 @@ function scrollValue(position) { // Select and initilize sticky table headers. function tableHeaderInitHandler(e) { + TableHeader.displacements = window.parent.Drupal.displace.getOffsets(true); var $tables = $(e.data.context).find('table.sticky-enabled').once('tableheader'); for (var i = 0, il = $tables.length; i < il; i++) { TableHeader.tables.push(new TableHeader($tables[i])); } + // Trigger a scroll event to prime sticky headers that may be applicable. + $(window).trigger('scroll.TableHeader'); } // Helper method to loop through tables and execute a method. @@ -39,16 +42,16 @@ function tableHeaderOnScrollHandler(e) { forTables('onScroll'); } -function tableHeaderOffsetChangeHandler(e) { +function tableHeaderOffsetChangeHandler(e, offsets) { // Compute the new offset value. - TableHeader.computeOffsetTop(); - forTables('stickyPosition', TableHeader.offsetTop); + TableHeader.displacements = 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 +69,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 +80,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. * @@ -122,24 +122,15 @@ $.extend(TableHeader, { tables: [], /** - * Cache of computed offset value. + * Cache of computed viewport displacement values. * * @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; + displacements: { + top: 0, + right: 0, + bottom: 0, + left: 0 } }); @@ -211,7 +202,7 @@ $.extend(TableHeader.prototype, { */ checkStickyVisible: function () { var scrollTop = scrollValue('scrollTop'); - var tableTop = this.tableOffset.top - TableHeader.offsetTop; + var tableTop = this.tableOffset.top - TableHeader.displacements.top; var tableBottom = tableTop + this.tableHeight; var visible = false; @@ -230,7 +221,7 @@ $.extend(TableHeader.prototype, { * * @param event */ - onScroll: function (e) { + onScroll: function (event) { this.checkStickyVisible(); // Track horizontal positioning relative to the viewport. this.stickyPosition(null, scrollValue('scrollLeft')); @@ -248,9 +239,8 @@ $.extend(TableHeader.prototype, { this.tableHeight = this.$originalTable[0].clientHeight; // Update offset top. - TableHeader.computeOffsetTop(); this.tableOffset = this.$originalTable.offset(); - this.stickyPosition(TableHeader.offsetTop); + this.stickyPosition(TableHeader.displacements.top, scrollValue('scrollLeft')); // Update columns width. var $that = null; @@ -277,4 +267,4 @@ $.extend(TableHeader.prototype, { // Expose constructor in the public space. Drupal.TableHeader = TableHeader; -}(jQuery, Drupal)); +}(jQuery, Drupal, window, window.document)); diff --git a/core/modules/overlay/overlay-child.css b/core/modules/overlay/overlay-child.css index 23b63d9..a51dfd4 100644 --- a/core/modules/overlay/overlay-child.css +++ b/core/modules/overlay/overlay-child.css @@ -16,14 +16,17 @@ } #overlay { - display: table; + box-sizing: border-box; + display: block; margin: 0 auto; + max-width: 50%; min-height: 100px; - min-width: 700px; + padding-left: 40px; + padding-right: 40px; position: relative; - width: 50%; box-shadow: 0 0 2em 0 rgba(0,0,0,0.5); } + #overlay-content { clear: both; color: #000; diff --git a/core/modules/overlay/overlay-child.js b/core/modules/overlay/overlay-child.js index 8675a3d..160103e 100644 --- a/core/modules/overlay/overlay-child.js +++ b/core/modules/overlay/overlay-child.js @@ -3,7 +3,7 @@ * Attaches the behaviors for the Overlay child pages. */ -(function ($) { +(function ($, window, document) { "use strict"; @@ -162,11 +162,4 @@ Drupal.overlayChild.behaviors.tabs = 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 () { - // Fires an event that the child iframe can listen to. - $(document).trigger('offsettopchange'); -}); - -})(jQuery); +})(jQuery, window, window.document); diff --git a/core/modules/overlay/overlay-parent.js b/core/modules/overlay/overlay-parent.js index 9965298..60d8652 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')) @@ -139,11 +144,9 @@ Drupal.overlay.create = function () { ' drupalOverlayBeforeLoad' + eventClass + ' drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerDispatchEvent')); - if ($('.overlay-displace-top, .overlay-displace-bottom').length) { - $(document) - .bind('drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerAlterDisplacedElements')) - .bind('drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerRestoreDisplacedElements')); - } + $(document) + .bind('drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerAlterDisplacedElements')) + .bind('drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerRestoreDisplacedElements')); }; /** @@ -398,6 +401,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,22 +446,28 @@ 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 }); + $(Drupal.overlay.iframeWindow.document).trigger('drupalViewportOffsetChange', Drupal.overlay.viewportOffsets); + var documentHeight = this.iframeWindow.document.body.clientHeight; var documentWidth = this.iframeWindow.document.body.clientWidth; // IE6 doesn't support maxWidth, use width instead. var maxWidthName = 'maxWidth'; + // If either the documentWidth or documentHeight are a zero dimension, abort + // the effort to alter presentation elements. + if (documentWidth === 0 || documentHeight === 0) { + return; + } + if (Drupal.overlay.leftSidedScrollbarOffset === undefined && $(document.documentElement).attr('dir') === 'rtl') { // We can't use element.clientLeft to detect whether scrollbars are placed // on the left side of the element when direction is set to "rtl" as most @@ -474,7 +491,7 @@ Drupal.overlay.eventhandlerAlterDisplacedElements = function (event) { // Consider any element that should be visible above the overlay (such as // a toolbar). - $('.overlay-displace-top, .overlay-displace-bottom').each(function () { + $(Drupal.displace.getElements().top).add(Drupal.displace.getElements().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/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 315add7..7b2ac26 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1397,6 +1397,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', @@ -2093,6 +2108,7 @@ function system_library_info() { array('system', 'drupal'), array('system', 'drupalSettings'), array('system', 'jquery.once'), + array('system', 'drupal.displace'), ), ); $libraries['drupal.timezone'] = array( 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..33c7133 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); @@ -158,9 +164,9 @@ Drupal.toolbar.toggleTray = function (event) { // Set aria-pressed to false. .attr('aria-pressed', 'false'); $toolbar.find('.tray').not($activateTray).removeClass('active'); - // Update the page and toolbar dimension indicators. - updatePeripherals(); } + // Update the page and toolbar dimension indicators. + updatePeripherals(); }; /** @@ -184,6 +190,9 @@ Drupal.toolbar.setHeight = function () { /** * Get the height of the active tray and include it in the total * height of the toolbar. + * + * If the height of the bar changed, Drupal.displace is called so that + * elements can adjust to the placement of the bar. */ height += $trays.filter('.active.horizontal').outerHeight() || 0; // Indicate the height of the toolbar in the attribute data-offset-top. @@ -192,8 +201,25 @@ 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'); + // Trigger a recalculation of viewport displacing elements. + Drupal.displace(); + } +}; + +/** + * Sets the width of a vertical tray in a data attribute. + * + * If the width of the tray changed, Drupal.displace is called so that elements + * 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(); } }; @@ -296,6 +322,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..5cd1f5b 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'), ), ), ); @@ -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(); @@ -631,6 +630,7 @@ function toolbar_library_info() { array('system', 'matchmedia'), array('system', 'jquery.once'), array('system', 'drupal.debounce'), + array('system', 'drupal.displace'), array('toolbar', 'toolbar.menu'), ), ); diff --git a/core/themes/bartik/css/style.css b/core/themes/bartik/css/style.css index 26534c7..27e2e0a 100644 --- a/core/themes/bartik/css/style.css +++ b/core/themes/bartik/css/style.css @@ -1622,7 +1622,7 @@ div.admin-panel .description { /** * Responsive tables. */ -@media screen and (max-width:28.125em) { /* 450px */ +@media screen and (max-width: 37.5em) { /* 600px */ th.priority-low, td.priority-low, th.priority-medium, @@ -1630,7 +1630,7 @@ div.admin-panel .description { display: none; } } -@media screen and (max-width:45em) { /* 720px */ +@media screen and (max-width: 60em) { /* 920px */ th.priority-low, td.priority-low { display: none; diff --git a/core/themes/seven/style.css b/core/themes/seven/style.css index 72ce5e6..6440294 100644 --- a/core/themes/seven/style.css +++ b/core/themes/seven/style.css @@ -522,7 +522,7 @@ table.system-status-report tr.error { /** * Responsive tables. */ -@media screen and (max-width:28.125em) { /* 450px */ +@media screen and (max-width: 37.5em) { /* 600px */ th.priority-low, td.priority-low, th.priority-medium, @@ -530,7 +530,7 @@ table.system-status-report tr.error { display: none; } } -@media screen and (max-width:45em) { /* 720px */ +@media screen and (max-width: 60em) { /* 920px */ th.priority-low, td.priority-low { display: none; -- 1.7.10.4