dialog.ajax.js 7.9 KB

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