annotate core/misc/dialog/dialog.ajax.es6.js @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 /**
Chris@0 2 * @file
Chris@0 3 * Extends the Drupal AJAX functionality to integrate the dialog API.
Chris@0 4 */
Chris@0 5
Chris@17 6 (function($, Drupal) {
Chris@0 7 /**
Chris@0 8 * Initialize dialogs for Ajax purposes.
Chris@0 9 *
Chris@0 10 * @type {Drupal~behavior}
Chris@0 11 *
Chris@0 12 * @prop {Drupal~behaviorAttach} attach
Chris@0 13 * Attaches the behaviors for dialog ajax functionality.
Chris@0 14 */
Chris@0 15 Drupal.behaviors.dialog = {
Chris@0 16 attach(context, settings) {
Chris@0 17 const $context = $(context);
Chris@0 18
Chris@0 19 // Provide a known 'drupal-modal' DOM element for Drupal-based modal
Chris@0 20 // dialogs. Non-modal dialogs are responsible for creating their own
Chris@0 21 // elements, since there can be multiple non-modal dialogs at a time.
Chris@0 22 if (!$('#drupal-modal').length) {
Chris@0 23 // Add 'ui-front' jQuery UI class so jQuery UI widgets like autocomplete
Chris@0 24 // sit on top of dialogs. For more information see
Chris@0 25 // http://api.jqueryui.com/theming/stacking-elements/.
Chris@17 26 $('<div id="drupal-modal" class="ui-front"/>')
Chris@17 27 .hide()
Chris@17 28 .appendTo('body');
Chris@0 29 }
Chris@0 30
Chris@0 31 // Special behaviors specific when attaching content within a dialog.
Chris@0 32 // These behaviors usually fire after a validation error inside a dialog.
Chris@0 33 const $dialog = $context.closest('.ui-dialog-content');
Chris@0 34 if ($dialog.length) {
Chris@0 35 // Remove and replace the dialog buttons with those from the new form.
Chris@0 36 if ($dialog.dialog('option', 'drupalAutoButtons')) {
Chris@0 37 // Trigger an event to detect/sync changes to buttons.
Chris@0 38 $dialog.trigger('dialogButtonsChange');
Chris@0 39 }
Chris@0 40
Chris@0 41 // Force focus on the modal when the behavior is run.
Chris@0 42 $dialog.dialog('widget').trigger('focus');
Chris@0 43 }
Chris@0 44
Chris@0 45 const originalClose = settings.dialog.close;
Chris@0 46 // Overwrite the close method to remove the dialog on closing.
Chris@17 47 settings.dialog.close = function(event, ...args) {
Chris@14 48 originalClose.apply(settings.dialog, [event, ...args]);
Chris@0 49 $(event.target).remove();
Chris@0 50 };
Chris@0 51 },
Chris@0 52
Chris@0 53 /**
Chris@0 54 * Scan a dialog for any primary buttons and move them to the button area.
Chris@0 55 *
Chris@0 56 * @param {jQuery} $dialog
Chris@0 57 * An jQuery object containing the element that is the dialog target.
Chris@0 58 *
Chris@0 59 * @return {Array}
Chris@0 60 * An array of buttons that need to be added to the button area.
Chris@0 61 */
Chris@0 62 prepareDialogButtons($dialog) {
Chris@0 63 const buttons = [];
Chris@17 64 const $buttons = $dialog.find(
Chris@17 65 '.form-actions input[type=submit], .form-actions a.button',
Chris@17 66 );
Chris@17 67 $buttons.each(function() {
Chris@0 68 // Hidden form buttons need special attention. For browser consistency,
Chris@0 69 // the button needs to be "visible" in order to have the enter key fire
Chris@0 70 // the form submit event. So instead of a simple "hide" or
Chris@0 71 // "display: none", we set its dimensions to zero.
Chris@0 72 // See http://mattsnider.com/how-forms-submit-when-pressing-enter/
Chris@0 73 const $originalButton = $(this).css({
Chris@0 74 display: 'block',
Chris@0 75 width: 0,
Chris@0 76 height: 0,
Chris@0 77 padding: 0,
Chris@0 78 border: 0,
Chris@0 79 overflow: 'hidden',
Chris@0 80 });
Chris@0 81 buttons.push({
Chris@0 82 text: $originalButton.html() || $originalButton.attr('value'),
Chris@0 83 class: $originalButton.attr('class'),
Chris@0 84 click(e) {
Chris@0 85 // If the original button is an anchor tag, triggering the "click"
Chris@0 86 // event will not simulate a click. Use the click method instead.
Chris@0 87 if ($originalButton.is('a')) {
Chris@0 88 $originalButton[0].click();
Chris@17 89 } else {
Chris@17 90 $originalButton
Chris@17 91 .trigger('mousedown')
Chris@17 92 .trigger('mouseup')
Chris@17 93 .trigger('click');
Chris@0 94 e.preventDefault();
Chris@0 95 }
Chris@0 96 },
Chris@0 97 });
Chris@0 98 });
Chris@0 99 return buttons;
Chris@0 100 },
Chris@0 101 };
Chris@0 102
Chris@0 103 /**
Chris@0 104 * Command to open a dialog.
Chris@0 105 *
Chris@0 106 * @param {Drupal.Ajax} ajax
Chris@0 107 * The Drupal Ajax object.
Chris@0 108 * @param {object} response
Chris@0 109 * Object holding the server response.
Chris@0 110 * @param {number} [status]
Chris@0 111 * The HTTP status code.
Chris@0 112 *
Chris@0 113 * @return {bool|undefined}
Chris@0 114 * Returns false if there was no selector property in the response object.
Chris@0 115 */
Chris@17 116 Drupal.AjaxCommands.prototype.openDialog = function(ajax, response, status) {
Chris@0 117 if (!response.selector) {
Chris@0 118 return false;
Chris@0 119 }
Chris@0 120 let $dialog = $(response.selector);
Chris@0 121 if (!$dialog.length) {
Chris@0 122 // Create the element if needed.
Chris@17 123 $dialog = $(
Chris@17 124 `<div id="${response.selector.replace(/^#/, '')}" class="ui-front"/>`,
Chris@17 125 ).appendTo('body');
Chris@0 126 }
Chris@0 127 // Set up the wrapper, if there isn't one.
Chris@0 128 if (!ajax.wrapper) {
Chris@0 129 ajax.wrapper = $dialog.attr('id');
Chris@0 130 }
Chris@0 131
Chris@0 132 // Use the ajax.js insert command to populate the dialog contents.
Chris@0 133 response.command = 'insert';
Chris@0 134 response.method = 'html';
Chris@0 135 ajax.commands.insert(ajax, response, status);
Chris@0 136
Chris@0 137 // Move the buttons to the jQuery UI dialog buttons area.
Chris@0 138 if (!response.dialogOptions.buttons) {
Chris@0 139 response.dialogOptions.drupalAutoButtons = true;
Chris@17 140 response.dialogOptions.buttons = Drupal.behaviors.dialog.prepareDialogButtons(
Chris@17 141 $dialog,
Chris@17 142 );
Chris@0 143 }
Chris@0 144
Chris@0 145 // Bind dialogButtonsChange.
Chris@0 146 $dialog.on('dialogButtonsChange', () => {
Chris@0 147 const buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
Chris@0 148 $dialog.dialog('option', 'buttons', buttons);
Chris@0 149 });
Chris@0 150
Chris@0 151 // Open the dialog itself.
Chris@0 152 response.dialogOptions = response.dialogOptions || {};
Chris@0 153 const dialog = Drupal.dialog($dialog.get(0), response.dialogOptions);
Chris@0 154 if (response.dialogOptions.modal) {
Chris@0 155 dialog.showModal();
Chris@17 156 } else {
Chris@0 157 dialog.show();
Chris@0 158 }
Chris@0 159
Chris@0 160 // Add the standard Drupal class for buttons for style consistency.
Chris@17 161 $dialog
Chris@17 162 .parent()
Chris@17 163 .find('.ui-dialog-buttonset')
Chris@17 164 .addClass('form-actions');
Chris@0 165 };
Chris@0 166
Chris@0 167 /**
Chris@0 168 * Command to close a dialog.
Chris@0 169 *
Chris@0 170 * If no selector is given, it defaults to trying to close the modal.
Chris@0 171 *
Chris@0 172 * @param {Drupal.Ajax} [ajax]
Chris@0 173 * The ajax object.
Chris@0 174 * @param {object} response
Chris@0 175 * Object holding the server response.
Chris@0 176 * @param {string} response.selector
Chris@0 177 * The selector of the dialog.
Chris@0 178 * @param {bool} response.persist
Chris@0 179 * Whether to persist the dialog element or not.
Chris@0 180 * @param {number} [status]
Chris@0 181 * The HTTP status code.
Chris@0 182 */
Chris@17 183 Drupal.AjaxCommands.prototype.closeDialog = function(ajax, response, status) {
Chris@0 184 const $dialog = $(response.selector);
Chris@0 185 if ($dialog.length) {
Chris@0 186 Drupal.dialog($dialog.get(0)).close();
Chris@0 187 if (!response.persist) {
Chris@0 188 $dialog.remove();
Chris@0 189 }
Chris@0 190 }
Chris@0 191
Chris@0 192 // Unbind dialogButtonsChange.
Chris@0 193 $dialog.off('dialogButtonsChange');
Chris@0 194 };
Chris@0 195
Chris@0 196 /**
Chris@0 197 * Command to set a dialog property.
Chris@0 198 *
Chris@0 199 * JQuery UI specific way of setting dialog options.
Chris@0 200 *
Chris@0 201 * @param {Drupal.Ajax} [ajax]
Chris@0 202 * The Drupal Ajax object.
Chris@0 203 * @param {object} response
Chris@0 204 * Object holding the server response.
Chris@0 205 * @param {string} response.selector
Chris@0 206 * Selector for the dialog element.
Chris@0 207 * @param {string} response.optionsName
Chris@0 208 * Name of a key to set.
Chris@0 209 * @param {string} response.optionValue
Chris@0 210 * Value to set.
Chris@0 211 * @param {number} [status]
Chris@0 212 * The HTTP status code.
Chris@0 213 */
Chris@17 214 Drupal.AjaxCommands.prototype.setDialogOption = function(
Chris@17 215 ajax,
Chris@17 216 response,
Chris@17 217 status,
Chris@17 218 ) {
Chris@0 219 const $dialog = $(response.selector);
Chris@0 220 if ($dialog.length) {
Chris@0 221 $dialog.dialog('option', response.optionName, response.optionValue);
Chris@0 222 }
Chris@0 223 };
Chris@0 224
Chris@0 225 /**
Chris@0 226 * Binds a listener on dialog creation to handle the cancel link.
Chris@0 227 *
Chris@0 228 * @param {jQuery.Event} e
Chris@0 229 * The event triggered.
Chris@0 230 * @param {Drupal.dialog~dialogDefinition} dialog
Chris@0 231 * The dialog instance.
Chris@0 232 * @param {jQuery} $element
Chris@0 233 * The jQuery collection of the dialog element.
Chris@0 234 * @param {object} [settings]
Chris@0 235 * Dialog settings.
Chris@0 236 */
Chris@0 237 $(window).on('dialog:aftercreate', (e, dialog, $element, settings) => {
Chris@17 238 $element.on('click.dialog', '.dialog-cancel', e => {
Chris@0 239 dialog.close('cancel');
Chris@0 240 e.preventDefault();
Chris@0 241 e.stopPropagation();
Chris@0 242 });
Chris@0 243 });
Chris@0 244
Chris@0 245 /**
Chris@0 246 * Removes all 'dialog' listeners.
Chris@0 247 *
Chris@0 248 * @param {jQuery.Event} e
Chris@0 249 * The event triggered.
Chris@0 250 * @param {Drupal.dialog~dialogDefinition} dialog
Chris@0 251 * The dialog instance.
Chris@0 252 * @param {jQuery} $element
Chris@0 253 * jQuery collection of the dialog element.
Chris@0 254 */
Chris@0 255 $(window).on('dialog:beforeclose', (e, dialog, $element) => {
Chris@0 256 $element.off('.dialog');
Chris@0 257 });
Chris@17 258 })(jQuery, Drupal);