diff --git a/core/misc/displace.js b/core/misc/displace.js index b3b7ae9..a211137 100644 --- a/core/misc/displace.js +++ b/core/misc/displace.js @@ -11,15 +11,41 @@ }; /** + * Registers a resize hanlder on the window. + */ + Drupal.behaviors.drupalDisplace = { + attach: function (context, settings) { + // 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', Drupal.debounce(function (event) { + displace(true); + }, 200)); + } + }; + + /** * Informs listeners of the current offset dimensions. * - * @param Boolean refresh - * - When true or undefined, causes the current offsets values to be - * recalculated. + * @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 (refresh) { - if (typeof refresh === 'undefined' || refresh) { - offsets = calculateOffsets(); + function displace (broadcast) { + offsets = calculateOffsets(); + if (typeof broadcast === 'undefined' || broadcast) { $(document).trigger('drupalViewportOffsetChange', offsets); } return offsets; @@ -27,6 +53,11 @@ /** * 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 { @@ -45,9 +76,12 @@ * numeric value, that value will be used. If no value is provided, one will * be calculated using the element's dimensions and placement. * - * @param edge + * @param string edge + * The name of the edge to calculate. Can be 'top', 'right', + * 'bottom' or 'left'. * - * @return {number} + * @return number + * The viewport displacement distance for the requested edge. */ function calculateOffset (edge) { var edgeOffset = 0; @@ -55,8 +89,8 @@ 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; + if ($el.get(0).style.display === 'none') { + continue; } // If the offset data attribute contains a displacing value, use it. var displacement = parseInt($el.attr('data-offset-' + edge), 10); @@ -78,11 +112,14 @@ * Calculates displacement for element based on its dimensions and placement. * * @param jQuery $el - * - The jQuery element whose dimensions and placement will be measured. + * 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 + * 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 documentElement = document.documentElement; @@ -92,7 +129,7 @@ var placement = $el.offset()[ horizontal ? 'left' : 'top']; // Subtract scroll distance from placement to get the distance // to the edge of the viewport. - placement = placement - window['scroll' + (horizontal ? 'X' : 'Y')]; + placement = 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 diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js index d7ca7fe..84a3c28 100644 --- a/core/misc/tableheader.js +++ b/core/misc/tableheader.js @@ -17,7 +17,7 @@ function scrollValue(position) { // Select and initilize sticky table headers. function tableHeaderInitHandler(e) { - TableHeader.displacements = window.parent.Drupal.displace.getOffsets(true); + TableHeader.displacements = window.parent.Drupal.displace(false); 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])); @@ -219,7 +219,7 @@ $.extend(TableHeader.prototype, { * * @param event */ - onScroll: function () { + onScroll: function (e) { this.checkStickyVisible(); // Track horizontal positioning relative to the viewport. this.stickyPosition(null, scrollValue('scrollLeft')); diff --git a/core/modules/overlay/overlay-child-rtl.css b/core/modules/overlay/overlay-child-rtl.css index 4195530..9f0c363 100644 --- a/core/modules/overlay/overlay-child-rtl.css +++ b/core/modules/overlay/overlay-child-rtl.css @@ -12,26 +12,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; } /** diff --git a/core/modules/overlay/overlay-child.css b/core/modules/overlay/overlay-child.css index 5a5acc7..3bbf906 100644 --- a/core/modules/overlay/overlay-child.css +++ b/core/modules/overlay/overlay-child.css @@ -22,9 +22,7 @@ max-width: 80rem; min-height: 100px; position: relative; - padding-bottom: 2em; - padding-left: 40px; - padding-right: 40px; + padding: 2em 40px; width: 100%; } #overlay-titlebar { @@ -69,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; @@ -78,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; } /** diff --git a/core/modules/overlay/overlay-child.js b/core/modules/overlay/overlay-child.js index f8167ec..6044852 100644 --- a/core/modules/overlay/overlay-child.js +++ b/core/modules/overlay/overlay-child.js @@ -179,4 +179,14 @@ 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(parent.document).bind('drupalViewportOffsetChange', function (event, offsets) { + // Fires an event that the child iframe can listen to. + $(document).trigger('drupalViewportOffsetChange', offsets); + $(document).trigger('resize'); + }); +}; + })(jQuery); diff --git a/core/modules/overlay/overlay-parent.js b/core/modules/overlay/overlay-parent.js index 5935d4f..e7c1162 100644 --- a/core/modules/overlay/overlay-parent.js +++ b/core/modules/overlay/overlay-parent.js @@ -108,7 +108,7 @@ Drupal.overlay.open = function (url) { 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(); + this.viewportOffsets = Drupal.displace(); // Build the overlay container. this.$container = $(Drupal.theme('overlayContainer')) @@ -136,18 +136,18 @@ Drupal.overlay.create = function () { $(window) .bind('resize' + eventClass, $.proxy(this, 'eventhandlerOuterResize')); $(document) - .on('drupalViewportOffsetChange' + eventClass, $.proxy(this, 'eventhandlerViewportOffsetChange')) - .on('drupalOverlayLoad' + eventClass, $.proxy(this, 'eventhandlerOuterResize')) - .on('drupalOverlayReady' + eventClass + + .bind('drupalViewportOffsetChange' + eventClass, $.proxy(this, 'eventhandlerViewportOffsetChange')) + .bind('drupalOverlayLoad' + eventClass, $.proxy(this, 'eventhandlerOuterResize')) + .bind('drupalOverlayReady' + eventClass + ' drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerSyncURLFragment')) - .on('drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerRefreshPage')) - .on('drupalOverlayBeforeClose' + eventClass + + .bind('drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerRefreshPage')) + .bind('drupalOverlayBeforeClose' + eventClass + ' drupalOverlayBeforeLoad' + eventClass + ' drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerDispatchEvent')); $(document) - .on('drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerAlterDisplacedElements')) - .on('drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerRestoreDisplacedElements')); + .bind('drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerAlterDisplacedElements')) + .bind('drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerRestoreDisplacedElements')); }; /** @@ -402,11 +402,20 @@ Drupal.overlay.isExternalLink = function (url) { }; /** + * Responds to the drupalViewportOffsetChange event. * + * @param object event + * A jQuery event object. + * + * @param object offsets + * 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. */ Drupal.overlay.eventhandlerViewportOffsetChange = function (event, offsets) { Drupal.overlay.viewportOffsets = offsets; - Drupal.overlay.eventhandlerOuterResize(); + // Allow other scripts to respond to this event. + $(document).trigger('drupalOverlayResize'); } /** @@ -449,82 +458,27 @@ Drupal.overlay.eventhandlerAlterDisplacedElements = function (event) { var offsets = Drupal.overlay.viewportOffsets; - $(this.iframeWindow.document.body).css({ - '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 - // browsers dont't support it correctly. - // http://www.gtalbot.org/BugzillaSection/DocumentAllDHTMLproperties.html - // There seems to be absolutely no way to detect whether the scrollbar - // is on the left side in Opera; always expect scrollbar to be on the left. - if ($.browser.opera) { - Drupal.overlay.leftSidedScrollbarOffset = document.documentElement.clientWidth - this.iframeWindow.document.documentElement.clientWidth + this.iframeWindow.document.documentElement.clientLeft; - } - else if (this.iframeWindow.document.documentElement.clientLeft) { - Drupal.overlay.leftSidedScrollbarOffset = this.iframeWindow.document.documentElement.clientLeft; - } - else { - var el1 = $('
').appendTo(document.body); - var el2 = $('').appendTo(el1); - Drupal.overlay.leftSidedScrollbarOffset = parseInt(el2[0].offsetLeft - el1[0].offsetLeft, 10); - el1.remove(); - } + // Move the body of the iframe contentDocument inward a sufficient distance + // to prevent it from appearing underneath displacing elements like the + // toolbar. + var iframeBody = this.iframeWindow.document.body; + $(iframeBody).css({ + 'padding-top': offsets.top, + 'padding-right': offsets.right, + 'padding-bottom': offsets.bottom, + 'padding-left': offsets.left + }) + // Trigger a repaint. + iframeBody.style.display='none'; + iframeBody.offsetHeight; + iframeBody.style.display='block'; + + // Constrain the width of offsetting top and bottom elements, such as the + // toolbar, so that a scroll in the overlay iframe won't be occluded. + var iframeBodyWidth = iframeBody.clientWidth; + if (iframeBodyWidth > 0 && iframeBodyWidth < document.documentElement.clientWidth) { + $('[data-offset-top], [data-offset-bottom]').css('max-width', iframeBodyWidth); } - - // Consider any element that should be visible above the overlay (such as - // a toolbar). - $('[data-offset-top], [data-offset-bottom]').each(function () { - var data = $(this).data(); - var maxWidth = documentWidth; - // In IE, Shadow filter makes element to overlap the scrollbar with 1px. - if (this.filters && this.filters.length && this.filters.item('DXImageTransform.Microsoft.Shadow')) { - maxWidth -= 1; - } - - if (Drupal.overlay.leftSidedScrollbarOffset) { - $(this).css('left', Drupal.overlay.leftSidedScrollbarOffset); - } - - // Prevent displaced elements overlapping window's scrollbar. - var currentMaxWidth = parseInt($(this).css(maxWidthName), 10); - if ((data.drupalOverlay && data.drupalOverlay.maxWidth) || isNaN(currentMaxWidth) || currentMaxWidth > maxWidth || currentMaxWidth <= 0) { - $(this).css(maxWidthName, maxWidth); - (data.drupalOverlay = data.drupalOverlay || {}).maxWidth = true; - } - - // Use a more rigorous approach if the displaced element still overlaps - // window's scrollbar; clip the element on the right. - var offset = $(this).offset(); - var offsetRight = offset.left + $(this).outerWidth(); - if ((data.drupalOverlay && data.drupalOverlay.clip) || offsetRight > maxWidth) { - if (Drupal.overlay.leftSidedScrollbarOffset) { - $(this).css('clip', 'rect(auto, auto, ' + (documentHeight - offset.top) + 'px, ' + (Drupal.overlay.leftSidedScrollbarOffset + 2) + 'px)'); - } - else { - $(this).css('clip', 'rect(auto, ' + (maxWidth - offset.left) + 'px, ' + (documentHeight - offset.top) + 'px, auto)'); - } - (data.drupalOverlay = data.drupalOverlay || {}).clip = true; - } - }); }; /** @@ -537,16 +491,7 @@ Drupal.overlay.eventhandlerAlterDisplacedElements = function (event) { * - event.currentTarget: any */ Drupal.overlay.eventhandlerRestoreDisplacedElements = function (event) { - var $displacedElements = $('.overlay-displace-top, .overlay-displace-bottom'); - try { - $displacedElements.css({ maxWidth: '', clip: '' }); - } - // IE bug that doesn't allow unsetting style.clip (http://dev.jquery.com/ticket/6512). - catch (err) { - $displacedElements.attr('style', function (index, attr) { - return attr.replace(/clip\s*:\s*rect\([^)]+\);?/i, ''); - }); - } + $('[data-offset-top], [data-offset-bottom]').css('max-width', 'none'); }; /** @@ -846,7 +791,7 @@ Drupal.overlay.resetActiveClass = function(activePath) { var self = this; var windowDomain = window.location.protocol + window.location.hostname; - $('.overlay-displace-top, .overlay-displace-bottom') + $('#toolbar-administration') .find('a[href]') // Remove active class from all links in displaced elements. .removeClass('active') @@ -889,24 +834,6 @@ Drupal.overlay.getPath = function (link) { }; /** - * Get the total displacement of given region. - * - * @param region - * Region name. Either "top" or "bottom". - * - * @return - * The total displacement of given region in pixels. - */ -Drupal.overlay.getDisplacement = function (region) { - var displacement = 0; - var lastDisplaced = $('[data-offset-' + region + ']'); - if (lastDisplaced.length) { - displacement = parseInt(lastDisplaced.attr('data-offset-' + region)); - } - return displacement; -}; - -/** * Makes elements outside the overlay unreachable via the tab key. * * @param context @@ -934,7 +861,7 @@ Drupal.overlay.makeDocumentUntabbable = function (context) { // If another element (like a div) has a tabindex, it's also tabbable. $tabbable = $tabbable.add($hasTabindex); // Leave links inside the overlay and toolbars alone. - $overlay = $('.overlay-element, #overlay-container, .overlay-displace-top, .overlay-displace-bottom').find('*'); + $overlay = $('.overlay-element, #overlay-container, #toolbar-administration').find('*'); $tabbable = $tabbable.not($overlay); // We now have a list of everything in the underlying document that could // possibly be reachable via the tab key. Make it all unreachable. diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 07961de..d0aed29 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1399,8 +1399,9 @@ function system_library_info() { ), ); - // A utility that measures elements like the toolbar that can potentially - // displace the positioning of display elements like the overlay. + // A utility that measures and reports viewport offset dimensions from + // elements like the toolbar that can potentially displace the positioning of + // elements like the overlay. $libraries['drupal.displace'] = array( 'title' => 'Drupal displace', 'version' => VERSION, diff --git a/core/modules/toolbar/css/toolbar.theme-rtl.css b/core/modules/toolbar/css/toolbar.theme-rtl.css index fa5a1df..031bc60 100644 --- a/core/modules/toolbar/css/toolbar.theme-rtl.css +++ b/core/modules/toolbar/css/toolbar.theme-rtl.css @@ -3,8 +3,17 @@ */ /** + * Toolbar bar. + */ +.toolbar .bar { + box-shadow: 1px 0 3px 1px rgba(0, 0, 0, 0.3333); +} +/** * Toolbar tray. */ + .toolbar .horizontal { + box-shadow: 2px 1px 3px 1px rgba(0, 0, 0, 0.3333); +} .toolbar .horizontal > .lining { padding-right: 0; padding-left: 5em; diff --git a/core/modules/toolbar/css/toolbar.theme.css b/core/modules/toolbar/css/toolbar.theme.css index c1317e5..4120135 100644 --- a/core/modules/toolbar/css/toolbar.theme.css +++ b/core/modules/toolbar/css/toolbar.theme.css @@ -28,7 +28,7 @@ */ .toolbar .bar { background-color: #0f0f0f; - box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.3333); + box-shadow: -1px 0 3px 1px rgba(0, 0, 0, 0.3333); /* LTR */ color: #dddddd; } .toolbar .bar a { @@ -66,7 +66,7 @@ } .toolbar .horizontal { border-bottom: 1px solid #aaaaaa; - box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.3333); + box-shadow: -2px 1px 3px 1px rgba(0, 0, 0, 0.3333); /* LTR */ } .toolbar .horizontal .tray { background-color: #f5f5f5; diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js index ce9970c..446f1e6 100644 --- a/core/modules/toolbar/js/toolbar.js +++ b/core/modules/toolbar/js/toolbar.js @@ -81,12 +81,9 @@ Drupal.behaviors.toolbar = { changeOrientation((locked) ? 'vertical' : ((mql.wide.matches) ? 'horizontal' : 'vertical'), locked); // Render the main menu as a nested, collapsible accordion. $toolbar.find('.toolbar-menu-administration > .menu').toolbarMenu(); - // 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); - // Attach behavior to the window. - $(window) - .on('resize.toolbar', setHeight); + // Attach behaviors to the document. + $(document) + .on('drupalViewportOffsetChange.toolbar', Drupal.toolbar.adjustPlacement); // Attach behaviors to the toolbar. $toolbar .on('click.toolbar', '.bar a', Drupal.toolbar.toggleTray) @@ -99,6 +96,8 @@ Drupal.behaviors.toolbar = { // Update the page and toolbar dimension indicators. updatePeripherals(); } + // Call displace to get the initial placement of offset elements. + Drupal.displace(); } }, // Default options. @@ -164,12 +163,16 @@ Drupal.toolbar.toggleTray = function (event) { }; /** - * The height of the toolbar offsets the top of the page content. + * Repositions trays and sets body padding according to the height of the bar. * - * Page components can register with the offsettopchange event to know when - * the height of the toolbar changes. + * @param {Event} event + * - jQuery Event object. + * + * @param {Object} offsets + * - Contains for keys -- top, right, bottom and left -- that indicate the + * viewport offset distances calculated by Drupal.displace(). */ -Drupal.toolbar.setHeight = function () { +Drupal.toolbar.adjustPlacement = function (event, offsets) { // Set the top of the all the trays to the height of the bar. var barHeight = $toolbar.find('.bar').outerHeight(); var height = barHeight; @@ -181,23 +184,8 @@ Drupal.toolbar.setHeight = function () { tray.style.top = bhpx; } } - /** - * 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. - var offset = parseInt($toolbar.attr('data-offset-top'), 10); - if (offset !== height) { - $toolbar.attr('data-offset-top', height); - // Alter the padding on the top of the body element. - $('body').css('padding-top', height); - // Trigger a recalculation of viewport displacing elements. - Drupal.displace(); - } + // Alter the padding on the top of the body element. + $('body').css('padding-top', offsets.top); }; /** @@ -207,10 +195,14 @@ Drupal.toolbar.setHeight = function () { * can adjust to the placement of the tray. */ Drupal.toolbar.setTrayWidth = function () { + var dir = document.documentElement.dir; + var edge = (dir === 'rtl') ? 'right' : 'left'; // Remove the left offset from the trays. - $toolbar.find('.tray').removeAttr('data-offset-left'); + $toolbar.find('.tray').removeAttr('data-offset-' + edge + ' data-offset-top'); // If an active vertical tray exists, mark it as an offset element. - $toolbar.find('.tray.vertical.active').attr('data-offset-left', ''); + $toolbar.find('.tray.vertical.active').attr('data-offset-' + edge, ''); + // If an active horizontal tray exists, mark it as an offset element. + $toolbar.find('.tray.horizontal.active').attr('data-offset-top', ''); // Trigger a recalculation of viewport displacing elements. Drupal.displace(); }; @@ -312,8 +304,6 @@ function toggleOrientationToggle (orientation) { function updatePeripherals () { // Adjust the body to accommodate trays. 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 fc4ba82..2880a5d 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -101,7 +101,8 @@ function toolbar_element_info() { '#heading' => t('Toolbar items'), '#attributes' => array( 'id' => 'toolbar-bar', - 'class' => array('bar', 'clearfix'), + 'class' => array('bar', 'clearfix',), + 'data-offset-top' => array(), ), ), );