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