123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- /**
- * @file
- * Dialog API inspired by HTML5 dialog element.
- *
- * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element
- */
- (function ($, Drupal, drupalSettings) {
- 'use strict';
- /**
- * Default dialog options.
- *
- * @type {object}
- *
- * @prop {bool} [autoOpen=true]
- * @prop {string} [dialogClass='']
- * @prop {string} [buttonClass='button']
- * @prop {string} [buttonPrimaryClass='button--primary']
- * @prop {function} close
- */
- drupalSettings.dialog = {
- autoOpen: true,
- dialogClass: '',
- // Drupal-specific extensions: see dialog.jquery-ui.js.
- buttonClass: 'button',
- buttonPrimaryClass: 'button--primary',
- // When using this API directly (when generating dialogs on the client
- // side), you may want to override this method and do
- // `jQuery(event.target).remove()` as well, to remove the dialog on
- // closing.
- close: function (event) {
- Drupal.dialog(event.target).close();
- Drupal.detachBehaviors(event.target, null, 'unload');
- }
- };
- /**
- * @typedef {object} Drupal.dialog~dialogDefinition
- *
- * @prop {boolean} open
- * Is the dialog open or not.
- * @prop {*} returnValue
- * Return value of the dialog.
- * @prop {function} show
- * Method to display the dialog on the page.
- * @prop {function} showModal
- * Method to display the dialog as a modal on the page.
- * @prop {function} close
- * Method to hide the dialog from the page.
- */
- /**
- * Polyfill HTML5 dialog element with jQueryUI.
- *
- * @param {HTMLElement} element
- * The element that holds the dialog.
- * @param {object} options
- * jQuery UI options to be passed to the dialog.
- *
- * @return {Drupal.dialog~dialogDefinition}
- * The dialog instance.
- */
- Drupal.dialog = function (element, options) {
- var undef;
- var $element = $(element);
- var dialog = {
- open: false,
- returnValue: undef,
- show: function () {
- openDialog({modal: false});
- },
- showModal: function () {
- openDialog({modal: true});
- },
- close: closeDialog
- };
- function openDialog(settings) {
- settings = $.extend({}, drupalSettings.dialog, options, settings);
- // Trigger a global event to allow scripts to bind events to the dialog.
- $(window).trigger('dialog:beforecreate', [dialog, $element, settings]);
- $element.dialog(settings);
- dialog.open = true;
- $(window).trigger('dialog:aftercreate', [dialog, $element, settings]);
- }
- function closeDialog(value) {
- $(window).trigger('dialog:beforeclose', [dialog, $element]);
- $element.dialog('close');
- dialog.returnValue = value;
- dialog.open = false;
- $(window).trigger('dialog:afterclose', [dialog, $element]);
- }
- return dialog;
- };
- })(jQuery, Drupal, drupalSettings);
- ;
- /**
- * @file
- * Positioning extensions for dialogs.
- */
- /**
- * Triggers when content inside a dialog changes.
- *
- * @event dialogContentResize
- */
- (function ($, Drupal, drupalSettings, debounce, displace) {
- 'use strict';
- // autoResize option will turn off resizable and draggable.
- drupalSettings.dialog = $.extend({autoResize: true, maxHeight: '95%'}, drupalSettings.dialog);
- /**
- * Resets the current options for positioning.
- *
- * This is used as a window resize and scroll callback to reposition the
- * jQuery UI dialog. Although not a built-in jQuery UI option, this can
- * be disabled by setting autoResize: false in the options array when creating
- * a new {@link Drupal.dialog}.
- *
- * @function Drupal.dialog~resetSize
- *
- * @param {jQuery.Event} event
- * The event triggered.
- *
- * @fires event:dialogContentResize
- */
- function resetSize(event) {
- var positionOptions = ['width', 'height', 'minWidth', 'minHeight', 'maxHeight', 'maxWidth', 'position'];
- var adjustedOptions = {};
- var windowHeight = $(window).height();
- var option;
- var optionValue;
- var adjustedValue;
- for (var n = 0; n < positionOptions.length; n++) {
- option = positionOptions[n];
- optionValue = event.data.settings[option];
- if (optionValue) {
- // jQuery UI does not support percentages on heights, convert to pixels.
- if (typeof optionValue === 'string' && /%$/.test(optionValue) && /height/i.test(option)) {
- // Take offsets in account.
- windowHeight -= displace.offsets.top + displace.offsets.bottom;
- adjustedValue = parseInt(0.01 * parseInt(optionValue, 10) * windowHeight, 10);
- // Don't force the dialog to be bigger vertically than needed.
- if (option === 'height' && event.data.$element.parent().outerHeight() < adjustedValue) {
- adjustedValue = 'auto';
- }
- adjustedOptions[option] = adjustedValue;
- }
- }
- }
- // Offset the dialog center to be at the center of Drupal.displace.offsets.
- if (!event.data.settings.modal) {
- adjustedOptions = resetPosition(adjustedOptions);
- }
- event.data.$element
- .dialog('option', adjustedOptions)
- .trigger('dialogContentResize');
- }
- /**
- * Position the dialog's center at the center of displace.offsets boundaries.
- *
- * @function Drupal.dialog~resetPosition
- *
- * @param {object} options
- * Options object.
- *
- * @return {object}
- * Altered options object.
- */
- function resetPosition(options) {
- var offsets = displace.offsets;
- var left = offsets.left - offsets.right;
- var top = offsets.top - offsets.bottom;
- var leftString = (left > 0 ? '+' : '-') + Math.abs(Math.round(left / 2)) + 'px';
- var topString = (top > 0 ? '+' : '-') + Math.abs(Math.round(top / 2)) + 'px';
- options.position = {
- my: 'center' + (left !== 0 ? leftString : '') + ' center' + (top !== 0 ? topString : ''),
- of: window
- };
- return options;
- }
- $(window).on({
- 'dialog:aftercreate': function (event, dialog, $element, settings) {
- var autoResize = debounce(resetSize, 20);
- var eventData = {settings: settings, $element: $element};
- if (settings.autoResize === true || settings.autoResize === 'true') {
- $element
- .dialog('option', {resizable: false, draggable: false})
- .dialog('widget').css('position', 'fixed');
- $(window)
- .on('resize.dialogResize scroll.dialogResize', eventData, autoResize)
- .trigger('resize.dialogResize');
- $(document).on('drupalViewportOffsetChange.dialogResize', eventData, autoResize);
- }
- },
- 'dialog:beforeclose': function (event, dialog, $element) {
- $(window).off('.dialogResize');
- $(document).off('.dialogResize');
- }
- });
- })(jQuery, Drupal, drupalSettings, Drupal.debounce, Drupal.displace);
- ;
- /**
- * @file
- * Adds default classes to buttons for styling purposes.
- */
- (function ($) {
- 'use strict';
- $.widget('ui.dialog', $.ui.dialog, {
- options: {
- buttonClass: 'button',
- buttonPrimaryClass: 'button--primary'
- },
- _createButtons: function () {
- var opts = this.options;
- var primaryIndex;
- var $buttons;
- var index;
- var il = opts.buttons.length;
- for (index = 0; index < il; index++) {
- if (opts.buttons[index].primary && opts.buttons[index].primary === true) {
- primaryIndex = index;
- delete opts.buttons[index].primary;
- break;
- }
- }
- this._super();
- $buttons = this.uiButtonSet.children().addClass(opts.buttonClass);
- if (typeof primaryIndex !== 'undefined') {
- $buttons.eq(index).addClass(opts.buttonPrimaryClass);
- }
- }
- });
- })(jQuery);
- ;
- /**
- * @file
- * Extends the Drupal AJAX functionality to integrate the dialog API.
- */
- (function ($, Drupal) {
- 'use strict';
- /**
- * Initialize dialogs for Ajax purposes.
- *
- * @type {Drupal~behavior}
- *
- * @prop {Drupal~behaviorAttach} attach
- * Attaches the behaviors for dialog ajax functionality.
- */
- Drupal.behaviors.dialog = {
- attach: function (context, settings) {
- var $context = $(context);
- // Provide a known 'drupal-modal' DOM element for Drupal-based modal
- // dialogs. Non-modal dialogs are responsible for creating their own
- // elements, since there can be multiple non-modal dialogs at a time.
- if (!$('#drupal-modal').length) {
- // Add 'ui-front' jQuery UI class so jQuery UI widgets like autocomplete
- // sit on top of dialogs. For more information see
- // http://api.jqueryui.com/theming/stacking-elements/.
- $('<div id="drupal-modal" class="ui-front"/>').hide().appendTo('body');
- }
- // Special behaviors specific when attaching content within a dialog.
- // These behaviors usually fire after a validation error inside a dialog.
- var $dialog = $context.closest('.ui-dialog-content');
- if ($dialog.length) {
- // Remove and replace the dialog buttons with those from the new form.
- if ($dialog.dialog('option', 'drupalAutoButtons')) {
- // Trigger an event to detect/sync changes to buttons.
- $dialog.trigger('dialogButtonsChange');
- }
- // Force focus on the modal when the behavior is run.
- $dialog.dialog('widget').trigger('focus');
- }
- var originalClose = settings.dialog.close;
- // Overwrite the close method to remove the dialog on closing.
- settings.dialog.close = function (event) {
- originalClose.apply(settings.dialog, arguments);
- $(event.target).remove();
- };
- },
- /**
- * Scan a dialog for any primary buttons and move them to the button area.
- *
- * @param {jQuery} $dialog
- * An jQuery object containing the element that is the dialog target.
- *
- * @return {Array}
- * An array of buttons that need to be added to the button area.
- */
- prepareDialogButtons: function ($dialog) {
- var buttons = [];
- var $buttons = $dialog.find('.form-actions input[type=submit], .form-actions a.button');
- $buttons.each(function () {
- // Hidden form buttons need special attention. For browser consistency,
- // the button needs to be "visible" in order to have the enter key fire
- // the form submit event. So instead of a simple "hide" or
- // "display: none", we set its dimensions to zero.
- // See http://mattsnider.com/how-forms-submit-when-pressing-enter/
- var $originalButton = $(this).css({
- display: 'block',
- width: 0,
- height: 0,
- padding: 0,
- border: 0,
- overflow: 'hidden'
- });
- buttons.push({
- text: $originalButton.html() || $originalButton.attr('value'),
- class: $originalButton.attr('class'),
- click: function (e) {
- // If the original button is an anchor tag, triggering the "click"
- // event will not simulate a click. Use the click method instead.
- if ($originalButton.is('a')) {
- $originalButton[0].click();
- }
- else {
- $originalButton.trigger('mousedown').trigger('mouseup').trigger('click');
- e.preventDefault();
- }
- }
- });
- });
- return buttons;
- }
- };
- /**
- * Command to open a dialog.
- *
- * @param {Drupal.Ajax} ajax
- * The Drupal Ajax object.
- * @param {object} response
- * Object holding the server response.
- * @param {number} [status]
- * The HTTP status code.
- *
- * @return {bool|undefined}
- * Returns false if there was no selector property in the response object.
- */
- Drupal.AjaxCommands.prototype.openDialog = function (ajax, response, status) {
- if (!response.selector) {
- return false;
- }
- var $dialog = $(response.selector);
- if (!$dialog.length) {
- // Create the element if needed.
- $dialog = $('<div id="' + response.selector.replace(/^#/, '') + '" class="ui-front"/>').appendTo('body');
- }
- // Set up the wrapper, if there isn't one.
- if (!ajax.wrapper) {
- ajax.wrapper = $dialog.attr('id');
- }
- // Use the ajax.js insert command to populate the dialog contents.
- response.command = 'insert';
- response.method = 'html';
- ajax.commands.insert(ajax, response, status);
- // Move the buttons to the jQuery UI dialog buttons area.
- if (!response.dialogOptions.buttons) {
- response.dialogOptions.drupalAutoButtons = true;
- response.dialogOptions.buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
- }
- // Bind dialogButtonsChange.
- $dialog.on('dialogButtonsChange', function () {
- var buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
- $dialog.dialog('option', 'buttons', buttons);
- });
- // Open the dialog itself.
- response.dialogOptions = response.dialogOptions || {};
- var dialog = Drupal.dialog($dialog.get(0), response.dialogOptions);
- if (response.dialogOptions.modal) {
- dialog.showModal();
- }
- else {
- dialog.show();
- }
- // Add the standard Drupal class for buttons for style consistency.
- $dialog.parent().find('.ui-dialog-buttonset').addClass('form-actions');
- };
- /**
- * Command to close a dialog.
- *
- * If no selector is given, it defaults to trying to close the modal.
- *
- * @param {Drupal.Ajax} [ajax]
- * The ajax object.
- * @param {object} response
- * Object holding the server response.
- * @param {string} response.selector
- * The selector of the dialog.
- * @param {bool} response.persist
- * Whether to persist the dialog element or not.
- * @param {number} [status]
- * The HTTP status code.
- */
- Drupal.AjaxCommands.prototype.closeDialog = function (ajax, response, status) {
- var $dialog = $(response.selector);
- if ($dialog.length) {
- Drupal.dialog($dialog.get(0)).close();
- if (!response.persist) {
- $dialog.remove();
- }
- }
- // Unbind dialogButtonsChange.
- $dialog.off('dialogButtonsChange');
- };
- /**
- * Command to set a dialog property.
- *
- * JQuery UI specific way of setting dialog options.
- *
- * @param {Drupal.Ajax} [ajax]
- * The Drupal Ajax object.
- * @param {object} response
- * Object holding the server response.
- * @param {string} response.selector
- * Selector for the dialog element.
- * @param {string} response.optionsName
- * Name of a key to set.
- * @param {string} response.optionValue
- * Value to set.
- * @param {number} [status]
- * The HTTP status code.
- */
- Drupal.AjaxCommands.prototype.setDialogOption = function (ajax, response, status) {
- var $dialog = $(response.selector);
- if ($dialog.length) {
- $dialog.dialog('option', response.optionName, response.optionValue);
- }
- };
- /**
- * Binds a listener on dialog creation to handle the cancel link.
- *
- * @param {jQuery.Event} e
- * The event triggered.
- * @param {Drupal.dialog~dialogDefinition} dialog
- * The dialog instance.
- * @param {jQuery} $element
- * The jQuery collection of the dialog element.
- * @param {object} [settings]
- * Dialog settings.
- */
- $(window).on('dialog:aftercreate', function (e, dialog, $element, settings) {
- $element.on('click.dialog', '.dialog-cancel', function (e) {
- dialog.close('cancel');
- e.preventDefault();
- e.stopPropagation();
- });
- });
- /**
- * Removes all 'dialog' listeners.
- *
- * @param {jQuery.Event} e
- * The event triggered.
- * @param {Drupal.dialog~dialogDefinition} dialog
- * The dialog instance.
- * @param {jQuery} $element
- * jQuery collection of the dialog element.
- */
- $(window).on('dialog:beforeclose', function (e, dialog, $element) {
- $element.off('.dialog');
- });
- })(jQuery, Drupal);
- ;
|