From 3f4174f99fc6e697e02f8a5d22805093150ce5ec Mon Sep 17 00:00:00 2001 From: Nathaniel Catchpole Date: Mon, 14 Aug 2017 15:36:51 +0900 Subject: [PATCH] Revert "Issue #2830882 by tedbow, droplet, Adita, drpal, markcarver, Wim Leers, nod_: Introduce Drupal.offCanvas, mirrored after Drupal.dialog, to avoid Settings Tray using Drupal.Dialog in unintended ways" This reverts commit 48339450ee875c1a4b4faa430bb0c0c6b337667c. --- core/modules/outside_in/js/off-canvas.es6.js | 325 +++++++------------ core/modules/outside_in/js/off-canvas.js | 186 +++++------ 2 files changed, 200 insertions(+), 311 deletions(-) diff --git a/core/modules/outside_in/js/off-canvas.es6.js b/core/modules/outside_in/js/off-canvas.es6.js index 507c4fe3d24c..480561a7c682 100644 --- a/core/modules/outside_in/js/off-canvas.es6.js +++ b/core/modules/outside_in/js/off-canvas.es6.js @@ -9,220 +9,101 @@ * @private */ -(($, Drupal, debounce, displace) => { +(function ($, Drupal, debounce, displace) { + // The minimum width to use body displace needs to match the width at which + // the tray will be %100 width. @see outside_in.module.css + const minDisplaceWidth = 768; + /** - * Off-canvas dialog implementation using jQuery Dialog. + * The edge of the screen that the dialog should appear on. * - * Transforms the regular dialogs created using Drupal.dialog when the dialog - * element equals '#drupal-off-canvas' into an side-loading dialog. - * - * @namespace + * @type {string} */ - Drupal.offCanvas = { + const edge = document.documentElement.dir === 'rtl' ? 'left' : 'right'; - /** - * The minimum width to use body displace needs to match the width at which - * the tray will be %100 width. @see outside_in.module.css - * @type {Number} - */ - minDisplaceWidth: 768, + const $mainCanvasWrapper = $('[data-off-canvas-main-canvas]'); - /** - * Wrapper used to position off-canvas dialog. - * @type {jQuery} - */ - $mainCanvasWrapper: $('[data-off-canvas-main-canvas]'), + /** + * Resets the size of the dialog. + * + * @param {jQuery.Event} event + * The event triggered. + */ + function resetSize(event) { + const offsets = displace.offsets; + const $element = event.data.$element; + const $widget = $element.dialog('widget'); + const $elementScroll = $element.scrollTop(); - /** - * Determines if an element is an off-canvas dialog. - * - * @param {jQuery} $element - * The dialog element. - * @return {bool} - * True this is currently an off-canvas dialog. - */ - isOffCanvas($element) { - return $element.is('#drupal-off-canvas'); - }, - - /** - * Handler fired before an off-canvas dialog has been opened. - * @param {Object} settings - * Settings related to the composition of the dialog. - * @return {undefined} - */ - beforeCreate(settings) { - $('body').addClass('js-tray-open'); - settings.dialogClass += ' ui-dialog-off-canvas'; + const adjustedOptions = { // @see http://api.jqueryui.com/position/ - settings.position = { - my: 'left top', - at: `${Drupal.offCanvas.getEdge()} top`, + position: { + my: `${edge} top`, + at: `${edge} top${offsets.top !== 0 ? `+${offsets.top}` : ''}`, of: window, - }; + }, + }; - /** - * Applies initial height to dialog based on window height. - * @see http://api.jqueryui.com/dialog for all dialog options. - */ - settings.height = $(window).height(); - }, + $widget.css({ + position: 'fixed', + height: `${$(window).height() - (offsets.top + offsets.bottom)}px`, + }); - /** - * Handler fired after an off-canvas dialog has been closed. - * @return {undefined} - */ - beforeClose() { - $('body').removeClass('js-tray-open'); - // Remove all *.off-canvas events - $(document).off('.off-canvas'); - $(window).off('.off-canvas'); - Drupal.offCanvas.$mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`, 0); - }, + $element + .dialog('option', adjustedOptions) + .trigger('dialogContentResize.off-canvas'); - /** - * Handler fired when an off-canvas dialog has been opened. - * @param {jQuery} $element - * The off-canvas dialog element. - * @param {Object} settings - * Settings related to the composition of the dialog. - * @return {undefined} - */ - afterCreate($element, settings) { - const eventData = { settings, $element, offCanvasDialog: this }; + // Reset the elements scroll position after being repositioned. + $element.scrollTop($elementScroll); + } - $element - .on('dialogresize.off-canvas', eventData, debounce(Drupal.offCanvas.bodyPadding, 100)) - .on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.handleDialogResize) - .on('dialogContentResize.off-canvas', eventData, debounce(Drupal.offCanvas.bodyPadding, 100)) - .trigger('dialogresize.off-canvas'); + /** + * Adjusts the dialog on resize. + * + * @param {jQuery.Event} event + * The event triggered. + */ + function handleDialogResize(event) { + const $element = event.data.$element; + const $widget = $element.dialog('widget'); - Drupal.offCanvas.getContainer($element).attr(`data-offset-${Drupal.offCanvas.getEdge()}`, ''); + const $offsets = $widget.find('> :not(#drupal-off-canvas, .ui-resizable-handle)'); + let offset = 0; + let modalHeight; - $(window) - .on('resize.off-canvas scroll.off-canvas', eventData, debounce(Drupal.offCanvas.resetSize, 100)) - .trigger('resize.off-canvas'); - }, + // Let scroll element take all the height available. + $element.css({ height: 'auto' }); + modalHeight = $widget.height(); + $offsets.each(function () { + offset += $(this).outerHeight(); + }); - /** - * Toggle classes based on title existence. - * Called with Drupal.offCanvas.afterCreate. - * @param {Object} settings - * Settings related to the composition of the dialog. - * @return {undefined} - */ - render(settings) { - $('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title); - }, + // Take internal padding into account. + const scrollOffset = $element.outerHeight() - $element.height(); + $element.height(modalHeight - offset - scrollOffset); + } - /** - * Adjusts the dialog on resize. - * - * @param {jQuery.Event} event - * The event triggered. - * @param {object} event.data - * Data attached to the event. - */ - handleDialogResize(event) { - const $element = event.data.$element; - const $container = Drupal.offCanvas.getContainer($element); + /** + * Adjusts the body padding when the dialog is resized. + * + * @param {jQuery.Event} event + * The event triggered. + */ + function bodyPadding(event) { + if ($('body').outerWidth() < minDisplaceWidth) { + return; + } + const $element = event.data.$element; + const $widget = $element.dialog('widget'); - const $offsets = $container.find('> :not(#drupal-off-canvas, .ui-resizable-handle)'); - let offset = 0; - - // Let scroll element take all the height available. - $element.css({ height: 'auto' }); - const modalHeight = $container.height(); - - $offsets.each(($offset) => { - offset += $($offset).outerHeight(); - }); - - // Take internal padding into account. - const scrollOffset = $element.outerHeight() - $element.height(); - $element.height(modalHeight - offset - scrollOffset); - }, - - /** - * Resets the size of the dialog. - * - * @param {jQuery.Event} event - * The event triggered. - * @param {object} event.data - * Data attached to the event. - */ - resetSize(event) { - const offsets = displace.offsets; - const $element = event.data.$element; - const container = Drupal.offCanvas.getContainer($element); - - const topPosition = (offsets.top !== 0 ? `+${offsets.top}` : ''); - const adjustedOptions = { - // @see http://api.jqueryui.com/position/ - position: { - my: `${Drupal.offCanvas.getEdge()} top`, - at: `${Drupal.offCanvas.getEdge()} top${topPosition}`, - of: window, - }, - }; - - container.css({ - position: 'fixed', - height: `${$(window).height() - (offsets.top + offsets.bottom)}px`, - }); - - $element - .dialog('option', adjustedOptions) - .trigger('dialogContentResize.off-canvas'); - }, - - /** - * Adjusts the body padding when the dialog is resized. - * - * @param {jQuery.Event} event - * The event triggered. - * @param {object} event.data - * Data attached to the event. - */ - bodyPadding(event) { - if ($('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth) { - return; - } - const $element = event.data.$element; - const $container = Drupal.offCanvas.getContainer($element); - const $mainCanvasWrapper = Drupal.offCanvas.$mainCanvasWrapper; - - const width = $container.outerWidth(); - const mainCanvasPadding = $mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`); - if (width !== mainCanvasPadding) { - $mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`, `${width}px`); - $container.attr(`data-offset-${Drupal.offCanvas.getEdge()}`, width); - displace(); - } - }, - - /** - * The HTML element that surrounds the dialog. - * @param {HTMLElement} $element - * The dialog element. - * - * @return {HTMLElement} - * The containing element. - */ - getContainer($element) { - return $element.dialog('widget'); - }, - - /** - * The edge of the screen that the dialog should appear on. - * - * @return {string} - * The edge the tray will be shown on, left or right. - */ - getEdge() { - return document.documentElement.dir === 'rtl' ? 'left' : 'right'; - }, - }; + const width = $widget.outerWidth(); + const mainCanvasPadding = $mainCanvasWrapper.css(`padding-${edge}`); + if (width !== mainCanvasPadding) { + $mainCanvasWrapper.css(`padding-${edge}`, `${width}px`); + $widget.attr(`data-offset-${edge}`, width); + displace(); + } + } /** * Attaches off-canvas dialog behaviors. @@ -233,25 +114,51 @@ * Attaches event listeners for off-canvas dialogs. */ Drupal.behaviors.offCanvasEvents = { - attach: () => { + attach() { $(window).once('off-canvas').on({ - 'dialog:beforecreate': (event, dialog, $element, settings) => { - if (Drupal.offCanvas.isOffCanvas($element)) { - Drupal.offCanvas.beforeCreate(settings); + 'dialog:aftercreate': function (event, dialog, $element, settings) { + if ($element.is('#drupal-off-canvas')) { + const eventData = { settings, $element }; + $('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title); + + $element + .on('dialogresize.off-canvas', eventData, debounce(bodyPadding, 100)) + .on('dialogContentResize.off-canvas', eventData, handleDialogResize) + .on('dialogContentResize.off-canvas', eventData, debounce(bodyPadding, 100)) + .trigger('dialogresize.off-canvas'); + + $element.dialog('widget').attr(`data-offset-${edge}`, ''); + + $(window) + .on('resize.off-canvas scroll.off-canvas', eventData, debounce(resetSize, 100)) + .trigger('resize.off-canvas'); } }, - 'dialog:aftercreate': (event, dialog, $element, settings) => { - if (Drupal.offCanvas.isOffCanvas($element)) { - Drupal.offCanvas.render(settings); - Drupal.offCanvas.afterCreate($element, settings); + 'dialog:beforecreate': function (event, dialog, $element, settings) { + if ($element.is('#drupal-off-canvas')) { + $('body').addClass('js-tray-open'); + // @see http://api.jqueryui.com/position/ + settings.position = { + my: 'left top', + at: `${edge} top`, + of: window, + }; + settings.dialogClass += ' ui-dialog-off-canvas'; + // Applies initial height to dialog based on window height. + // See http://api.jqueryui.com/dialog for all dialog options. + settings.height = $(window).height(); } }, - 'dialog:beforeclose': (event, dialog, $element) => { - if (Drupal.offCanvas.isOffCanvas($element)) { - Drupal.offCanvas.beforeClose(event, dialog, $element); + 'dialog:beforeclose': function (event, dialog, $element) { + if ($element.is('#drupal-off-canvas')) { + $('body').removeClass('js-tray-open'); + // Remove all *.off-canvas events + $(document).off('.off-canvas'); + $(window).off('.off-canvas'); + $mainCanvasWrapper.css(`padding-${edge}`, 0); } }, }); }, }; -})(jQuery, Drupal, Drupal.debounce, Drupal.displace); +}(jQuery, Drupal, Drupal.debounce, Drupal.displace)); diff --git a/core/modules/outside_in/js/off-canvas.js b/core/modules/outside_in/js/off-canvas.js index 84df39d319e5..85a9e5367580 100644 --- a/core/modules/outside_in/js/off-canvas.js +++ b/core/modules/outside_in/js/off-canvas.js @@ -6,124 +6,106 @@ **/ (function ($, Drupal, debounce, displace) { - Drupal.offCanvas = { - minDisplaceWidth: 768, + var minDisplaceWidth = 768; - $mainCanvasWrapper: $('[data-off-canvas-main-canvas]'), + var edge = document.documentElement.dir === 'rtl' ? 'left' : 'right'; - isOffCanvas: function isOffCanvas($element) { - return $element.is('#drupal-off-canvas'); - }, - beforeCreate: function beforeCreate(settings) { - $('body').addClass('js-tray-open'); - settings.dialogClass += ' ui-dialog-off-canvas'; + var $mainCanvasWrapper = $('[data-off-canvas-main-canvas]'); - settings.position = { - my: 'left top', - at: Drupal.offCanvas.getEdge() + ' top', + function resetSize(event) { + var offsets = displace.offsets; + var $element = event.data.$element; + var $widget = $element.dialog('widget'); + var $elementScroll = $element.scrollTop(); + + var adjustedOptions = { + position: { + my: edge + ' top', + at: edge + ' top' + (offsets.top !== 0 ? '+' + offsets.top : ''), of: window - }; - - settings.height = $(window).height(); - }, - beforeClose: function beforeClose() { - $('body').removeClass('js-tray-open'); - - $(document).off('.off-canvas'); - $(window).off('.off-canvas'); - Drupal.offCanvas.$mainCanvasWrapper.css('padding-' + Drupal.offCanvas.getEdge(), 0); - }, - afterCreate: function afterCreate($element, settings) { - var eventData = { settings: settings, $element: $element, offCanvasDialog: this }; - - $element.on('dialogresize.off-canvas', eventData, debounce(Drupal.offCanvas.bodyPadding, 100)).on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.handleDialogResize).on('dialogContentResize.off-canvas', eventData, debounce(Drupal.offCanvas.bodyPadding, 100)).trigger('dialogresize.off-canvas'); - - Drupal.offCanvas.getContainer($element).attr('data-offset-' + Drupal.offCanvas.getEdge(), ''); - - $(window).on('resize.off-canvas scroll.off-canvas', eventData, debounce(Drupal.offCanvas.resetSize, 100)).trigger('resize.off-canvas'); - }, - render: function render(settings) { - $('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title); - }, - handleDialogResize: function handleDialogResize(event) { - var $element = event.data.$element; - var $container = Drupal.offCanvas.getContainer($element); - - var $offsets = $container.find('> :not(#drupal-off-canvas, .ui-resizable-handle)'); - var offset = 0; - - $element.css({ height: 'auto' }); - var modalHeight = $container.height(); - - $offsets.each(function ($offset) { - offset += $($offset).outerHeight(); - }); - - var scrollOffset = $element.outerHeight() - $element.height(); - $element.height(modalHeight - offset - scrollOffset); - }, - resetSize: function resetSize(event) { - var offsets = displace.offsets; - var $element = event.data.$element; - var container = Drupal.offCanvas.getContainer($element); - - var topPosition = offsets.top !== 0 ? '+' + offsets.top : ''; - var adjustedOptions = { - position: { - my: Drupal.offCanvas.getEdge() + ' top', - at: Drupal.offCanvas.getEdge() + ' top' + topPosition, - of: window - } - }; - - container.css({ - position: 'fixed', - height: $(window).height() - (offsets.top + offsets.bottom) + 'px' - }); - - $element.dialog('option', adjustedOptions).trigger('dialogContentResize.off-canvas'); - }, - bodyPadding: function bodyPadding(event) { - if ($('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth) { - return; } - var $element = event.data.$element; - var $container = Drupal.offCanvas.getContainer($element); - var $mainCanvasWrapper = Drupal.offCanvas.$mainCanvasWrapper; + }; - var width = $container.outerWidth(); - var mainCanvasPadding = $mainCanvasWrapper.css('padding-' + Drupal.offCanvas.getEdge()); - if (width !== mainCanvasPadding) { - $mainCanvasWrapper.css('padding-' + Drupal.offCanvas.getEdge(), width + 'px'); - $container.attr('data-offset-' + Drupal.offCanvas.getEdge(), width); - displace(); - } - }, - getContainer: function getContainer($element) { - return $element.dialog('widget'); - }, - getEdge: function getEdge() { - return document.documentElement.dir === 'rtl' ? 'left' : 'right'; + $widget.css({ + position: 'fixed', + height: $(window).height() - (offsets.top + offsets.bottom) + 'px' + }); + + $element.dialog('option', adjustedOptions).trigger('dialogContentResize.off-canvas'); + + $element.scrollTop($elementScroll); + } + + function handleDialogResize(event) { + var $element = event.data.$element; + var $widget = $element.dialog('widget'); + + var $offsets = $widget.find('> :not(#drupal-off-canvas, .ui-resizable-handle)'); + var offset = 0; + var modalHeight = void 0; + + $element.css({ height: 'auto' }); + modalHeight = $widget.height(); + $offsets.each(function () { + offset += $(this).outerHeight(); + }); + + var scrollOffset = $element.outerHeight() - $element.height(); + $element.height(modalHeight - offset - scrollOffset); + } + + function bodyPadding(event) { + if ($('body').outerWidth() < minDisplaceWidth) { + return; } - }; + var $element = event.data.$element; + var $widget = $element.dialog('widget'); + + var width = $widget.outerWidth(); + var mainCanvasPadding = $mainCanvasWrapper.css('padding-' + edge); + if (width !== mainCanvasPadding) { + $mainCanvasWrapper.css('padding-' + edge, width + 'px'); + $widget.attr('data-offset-' + edge, width); + displace(); + } + } Drupal.behaviors.offCanvasEvents = { attach: function attach() { $(window).once('off-canvas').on({ - 'dialog:beforecreate': function dialogBeforecreate(event, dialog, $element, settings) { - if (Drupal.offCanvas.isOffCanvas($element)) { - Drupal.offCanvas.beforeCreate(settings); + 'dialog:aftercreate': function dialogAftercreate(event, dialog, $element, settings) { + if ($element.is('#drupal-off-canvas')) { + var eventData = { settings: settings, $element: $element }; + $('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title); + + $element.on('dialogresize.off-canvas', eventData, debounce(bodyPadding, 100)).on('dialogContentResize.off-canvas', eventData, handleDialogResize).on('dialogContentResize.off-canvas', eventData, debounce(bodyPadding, 100)).trigger('dialogresize.off-canvas'); + + $element.dialog('widget').attr('data-offset-' + edge, ''); + + $(window).on('resize.off-canvas scroll.off-canvas', eventData, debounce(resetSize, 100)).trigger('resize.off-canvas'); } }, - 'dialog:aftercreate': function dialogAftercreate(event, dialog, $element, settings) { - if (Drupal.offCanvas.isOffCanvas($element)) { - Drupal.offCanvas.render(settings); - Drupal.offCanvas.afterCreate($element, settings); + 'dialog:beforecreate': function dialogBeforecreate(event, dialog, $element, settings) { + if ($element.is('#drupal-off-canvas')) { + $('body').addClass('js-tray-open'); + + settings.position = { + my: 'left top', + at: edge + ' top', + of: window + }; + settings.dialogClass += ' ui-dialog-off-canvas'; + + settings.height = $(window).height(); } }, 'dialog:beforeclose': function dialogBeforeclose(event, dialog, $element) { - if (Drupal.offCanvas.isOffCanvas($element)) { - Drupal.offCanvas.beforeClose(event, dialog, $element); + if ($element.is('#drupal-off-canvas')) { + $('body').removeClass('js-tray-open'); + + $(document).off('.off-canvas'); + $(window).off('.off-canvas'); + $mainCanvasWrapper.css('padding-' + edge, 0); } } });