Mercurial > hg > isophonics-drupal-site
diff core/misc/dialog/off-canvas.es6.js @ 14:1fec387a4317
Update Drupal core to 8.5.2 via Composer
author | Chris Cannam |
---|---|
date | Mon, 23 Apr 2018 09:46:53 +0100 |
parents | |
children | 129ea1e6d783 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/misc/dialog/off-canvas.es6.js Mon Apr 23 09:46:53 2018 +0100 @@ -0,0 +1,273 @@ +/** + * @file + * Drupal's off-canvas library. + */ + +(($, Drupal, debounce, displace) => { + /** + * Off-canvas dialog implementation using jQuery Dialog. + * + * Transforms the regular dialogs created using Drupal.dialog when the dialog + * element equals '#drupal-off-canvas' into an side-loading dialog. + * + * @namespace + */ + Drupal.offCanvas = { + + /** + * The minimum width to use body displace needs to match the width at which + * the tray will be 100% width. @see core/misc/dialog/off-canvas.css + * + * @type {Number} + */ + minDisplaceWidth: 768, + + /** + * Wrapper used to position off-canvas dialog. + * + * @type {jQuery} + */ + $mainCanvasWrapper: $('[data-off-canvas-main-canvas]'), + + /** + * 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'); + }, + + /** + * Remove off-canvas dialog events. + * + * @param {jQuery} $element + * The target element. + */ + removeOffCanvasEvents($element) { + $element.off('.off-canvas'); + $(document).off('.off-canvas'); + $(window).off('.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, $element }) { + // Clean up previous dialog event handlers. + Drupal.offCanvas.removeOffCanvasEvents($element); + + $('body').addClass('js-off-canvas-dialog-open'); + // @see http://api.jqueryui.com/position/ + settings.position = { + my: 'left top', + at: `${Drupal.offCanvas.getEdge()} 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(); + }, + + /** + * Handler fired after an off-canvas dialog has been closed. + * + * @return {undefined} + */ + beforeClose({ $element }) { + $('body').removeClass('js-off-canvas-dialog-open'); + // Remove all *.off-canvas events + Drupal.offCanvas.removeOffCanvasEvents($element); + + Drupal.offCanvas.$mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`, 0); + }, + + /** + * 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 }; + + $element + .on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.handleDialogResize) + .on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.bodyPadding); + + Drupal.offCanvas.getContainer($element).attr(`data-offset-${Drupal.offCanvas.getEdge()}`, ''); + + $(window) + .on('resize.off-canvas', eventData, debounce(Drupal.offCanvas.resetSize, 100)) + .trigger('resize.off-canvas'); + }, + + /** + * 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); + }, + + /** + * 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); + + 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((i, e) => { + offset += $(e).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'; + }, + }; + + /** + * Attaches off-canvas dialog behaviors. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches event listeners for off-canvas dialogs. + */ + Drupal.behaviors.offCanvasEvents = { + attach: () => { + $(window).once('off-canvas').on({ + 'dialog:beforecreate': (event, dialog, $element, settings) => { + if (Drupal.offCanvas.isOffCanvas($element)) { + Drupal.offCanvas.beforeCreate({ dialog, $element, settings }); + } + }, + 'dialog:aftercreate': (event, dialog, $element, settings) => { + if (Drupal.offCanvas.isOffCanvas($element)) { + Drupal.offCanvas.render({ dialog, $element, settings }); + Drupal.offCanvas.afterCreate({ $element, settings }); + } + }, + 'dialog:beforeclose': (event, dialog, $element) => { + if (Drupal.offCanvas.isOffCanvas($element)) { + Drupal.offCanvas.beforeClose({ dialog, $element }); + } + }, + }); + }, + }; +})(jQuery, Drupal, Drupal.debounce, Drupal.displace);