Issue #1399256 by smithmilner: Detach jQuery behaviors when the Dialog closes.
[project/dialog.git] / dialog.module
1 <?php
2
3 /**
4 * @file
5 * The Dialog module provides an API for displaying and interacting with
6 * jQuery UI Dialog modals.
7 *
8 * This API is an integration with Drupal's AJAX Framework. Using the
9 * ajax "commands" provided, dialogs can be displayed, modified, and
10 * closed.
11 *
12 * @link
13 * http://api.drupal.org/api/group/ajax/7
14 * Drupal AJAX framework documentation.
15 */
16
17 /**
18 * Implementation of hook_page_alter().
19 */
20 function dialog_page_alter(&$page) {
21 // Alter the current page to display as a dialog box if desired.
22 if ($options = dialog_display()) {
23 // Construct the contents of the dialog box.
24 $content = render(drupal_set_page_content());
25
26 // Cleanse the dialog options.
27 if (!isset($options['title'])) {
28 $options['title'] = drupal_get_title();
29 }
30
31 // Send over the commands.
32 $commands = array();
33 $commands[] = dialog_command_display($content, $options);
34 ajax_render($commands);
35 }
36 }
37
38 /**
39 * Provides an easy way of representing the current page context as a dialog.
40 *
41 * @param $options
42 * (optional) If set, will become the options that are used when displaying the dialog
43 * to the user. See the jQuery UI Dialog options documentation for more
44 * information on this: http://jqueryui.com/demos/dialog/ .
45 *
46 * @return
47 * FALSE if the page is not to become a dialog box. Otherwise, will be an
48 * array of options that were previously set through the call to
49 * dialog_display. These options define how the resulting dialog box should
50 * be displayed.
51 */
52 function dialog_display($options = NULL) {
53 $dialog = &drupal_static(__FUNCTION__, FALSE);
54 if (isset($options)) {
55 // Make sure that an array is passed in as the options.
56 $dialog = is_array($options) ? $options : array('dialogClass' => drupal_html_class($_GET['q']));
57 }
58 return $dialog;
59 }
60
61 /**
62 * Implement hook_library().
63 */
64 function dialog_library() {
65 $path = drupal_get_path('module', 'dialog');
66
67 $libraries['dialog'] = array(
68 'title' => 'Dialog',
69 'website' => 'http://drupal.org/project/dialog',
70 'version' => '7.x',
71 'js' => array(
72 $path . '/jquery.xLazyLoader.js' => array('group' => JS_LIBRARY),
73 $path . '/dialog.js' => array('weight' => 5),
74 ),
75 'dependencies' => array(
76 array('system', 'drupal.ajax'),
77 array('system', 'jquery.form'),
78 array('system', 'ui.dialog'),
79 ),
80 );
81
82 return $libraries;
83 }
84
85 /**
86 * Check to see if the incoming menu item is able to use dialogs.
87 *
88 * @TODO: Move this to Drupal core?
89 */
90 function dialog_js_load($js = 'nojs') {
91 if ($js == 'ajax') {
92 return TRUE;
93 }
94 return 0;
95 }
96
97 /**
98 * Implement hook_ajax_render_alter().
99 *
100 * Using the xLazyLoader library and command, load additional css and
101 * javascript into the page.
102 *
103 * TODO: Deal with overloading one theme's css onto another.
104 */
105 function dialog_ajax_render_alter(&$commands) {
106 if (dialog_display()) {
107 $loader = array();
108 $allowed_media = array('all', 'screen');
109 // Inject additional JavaScript and CSS to the browser's client.
110 $css = drupal_add_css();
111 drupal_alter('css', $css);
112 foreach ($css as $data => $options) {
113 if ($options['type'] == 'file' && in_array($options['media'], $allowed_media)) {
114 $loader['css'][] = base_path() . $options['data'];
115 }
116 }
117 $scripts = drupal_add_js();
118 drupal_alter('js', $scripts);
119 foreach ($scripts as $data => $options) {
120 if ($options['type'] == 'file') {
121 $loader['js'][] = base_path() . $options['data'];
122 }
123 }
124 if (!empty($loader)) {
125 array_unshift($commands, dialog_command_xlazyloader($loader));
126 }
127
128 // Prepend status messages to the dialog content.
129 $commands[] = ajax_command_prepend('#dialog', theme('status_messages'));
130 }
131 }
132
133 /**
134 * Process a form and prepare it for the dialog.
135 */
136 function dialog_process_ajax_form($element) {
137 dialog_fix_element_id($element);
138 return $element;
139 }
140
141 /**
142 * Fix element and its chilren's id's so they are unique in the page.
143 */
144 function dialog_fix_element_id(&$element) {
145 if (!isset($element['#id'])) {
146 $element['#id'] = drupal_html_id('edit-' . implode('-', $element['#parents']));
147 }
148 $element['#id'] .= '-dialog';
149 foreach (element_children($element) as $child) {
150 // Don't squash an existing tree value.
151 if (!isset($element[$child]['#tree'])) {
152 $element[$child]['#tree'] = $element['#tree'];
153 }
154
155 // Don't squash existing parents value.
156 if (!isset($element[$child]['#parents'])) {
157 // Check to see if a tree of child elements is present. If so,
158 // continue down the tree if required.
159 $element[$child]['#parents'] = $element[$child]['#tree'] && $element['#tree'] ? array_merge($element['#parents'], array($child)) : array($child);
160 }
161
162 dialog_fix_element_id($element[$child]);
163 }
164 }
165
166 /**
167 * Creates a Drupal AJAX command to open the modal with a loading animation.
168 */
169 function dialog_command_loading() {
170 return array(
171 'command' => 'dialog_loading',
172 );
173 }
174
175 /**
176 * Creates a Drupal AJAX command to place HTML within the modal and open it.
177 *
178 * @param $content
179 * The contents of the dialog box. This can be either straight HTML, or a
180 * renderable array.
181 * @param $options
182 * An array of ui.dialog options. See the
183 * {@link http://jqueryui.com/demos/dialog/ jQuery UI Dialog} documentation
184 * for available options.
185 */
186 function dialog_command_display($content, $options = array()) {
187 return array(
188 'command' => 'dialog_display',
189 'content' => render($content),
190 'options' => $options,
191 );
192 }
193
194 /**
195 * Creates a Drupal AJAX command to close the modal.
196 */
197 function dialog_command_dismiss() {
198 return array(
199 'command' => 'dialog_dismiss',
200 );
201 }
202
203 /**
204 * Force a client-side redirect.
205 *
206 * @param $path
207 * The url to be redirected to.
208 * @param $options
209 * Any additional options for the URL.
210 */
211 function dialog_command_redirect($path, $options = array()) {
212 $options['absolute'] = TRUE;
213 return array(
214 'command' => 'dialog_redirect',
215 'url' => url($path, $options),
216 );
217 }
218
219 /**
220 * Force a client-side reload.
221 */
222 function dialog_command_reload() {
223 return array(
224 'command' => 'dialog_reload',
225 );
226 }
227
228 /**
229 * Creates a Drupal AJAX 'xLazyLoader' command.
230 *
231 * The 'xLazyLoader' command loads additional JavaScript, CSS and images through
232 * the xLazyLoader library (http://code.google.com/p/ajaxsoft/wiki/xLazyLoader).
233 *
234 * This command is implemented by Drupal.ajax.prototype.commands.xlazyloader()
235 * defined in dialog.js.
236 *
237 * @param $options
238 * An associative of what JavaScript, CSS or images the client should load.
239 * - "js": An array of JavaScript files to load.
240 * - "css": An array of CSS files to load.
241 * - "img": An array of images to load.
242 *
243 * @return
244 * An array suitable for use with the ajax_render() function.
245 */
246 function dialog_command_xlazyloader($options = array()) {
247 return array(
248 'command' => 'xlazyloader',
249 'options' => $options,
250 );
251 }