X-Git-Url: http://www.aleph1.co.uk/gitweb/?a=blobdiff_plain;ds=sidebyside;f=web%2Fcore%2Fmisc%2Fdialog%2Fdialog.ajax.es6.js;fp=web%2Fcore%2Fmisc%2Fdialog%2Fdialog.ajax.es6.js;h=798673a1d86c4990be33da05d846b114d246ddc2;hb=9917807b03b64faf00f6a1f29dcb6eafc454efa5;hp=0000000000000000000000000000000000000000;hpb=aea91e65e895364e460983b890e295aa5d5540a5;p=yaffs-website diff --git a/web/core/misc/dialog/dialog.ajax.es6.js b/web/core/misc/dialog/dialog.ajax.es6.js new file mode 100644 index 000000000..798673a1d --- /dev/null +++ b/web/core/misc/dialog/dialog.ajax.es6.js @@ -0,0 +1,242 @@ +/** + * @file + * Extends the Drupal AJAX functionality to integrate the dialog API. + */ + +(function ($, Drupal) { + /** + * Initialize dialogs for Ajax purposes. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches the behaviors for dialog ajax functionality. + */ + Drupal.behaviors.dialog = { + attach(context, settings) { + const $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/. + $('
').hide().appendTo('body'); + } + + // Special behaviors specific when attaching content within a dialog. + // These behaviors usually fire after a validation error inside a dialog. + const $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'); + } + + const 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($dialog) { + const buttons = []; + const $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/ + const $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(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; + } + let $dialog = $(response.selector); + if (!$dialog.length) { + // Create the element if needed. + $dialog = $(`
`).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', () => { + const buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog); + $dialog.dialog('option', 'buttons', buttons); + }); + + // Open the dialog itself. + response.dialogOptions = response.dialogOptions || {}; + const 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) { + const $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) { + const $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', (e, dialog, $element, settings) => { + $element.on('click.dialog', '.dialog-cancel', (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', (e, dialog, $element) => { + $element.off('.dialog'); + }); +}(jQuery, Drupal));