diff options
author | Dries Buytaert <dries@buytaert.net> | 2010-10-04 17:46:01 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2010-10-04 17:46:01 +0000 |
commit | 5a23b3fdb970bb0c3e79f47ba9296455d237d9f0 (patch) | |
tree | b9e59f7bdb1ffbbdc569c34f56980aba267ca3fa /includes/ajax.inc | |
parent | a50d47f9591d240f212b66332e25d7f2ce50369d (diff) | |
download | brdo-5a23b3fdb970bb0c3e79f47ba9296455d237d9f0.tar.gz brdo-5a23b3fdb970bb0c3e79f47ba9296455d237d9f0.tar.bz2 |
- Patch #561858 by effulgentsia, sun, rfay, Nick_vh, merlinofchaos, katbailey, dereine, tstoeckler: drupal_add_js() and drupal_add_css() to work for AJAX requests too by adding lazy-load to AJAX framework.
Diffstat (limited to 'includes/ajax.inc')
-rw-r--r-- | includes/ajax.inc | 96 |
1 files changed, 92 insertions, 4 deletions
diff --git a/includes/ajax.inc b/includes/ajax.inc index 2c987f035..bd590aa66 100644 --- a/includes/ajax.inc +++ b/includes/ajax.inc @@ -213,11 +213,66 @@ * functions. */ function ajax_render($commands = array()) { - // Automatically extract any 'settings' added via drupal_add_js() and make - // them the first command. - $scripts = drupal_add_js(NULL, NULL); + // AJAX responses aren't rendered with html.tpl.php, so we have to call + // drupal_get_css() and drupal_get_js() here, in order to have new files added + // during this request to be loaded by the page. We only want to send back + // files that the page hasn't already loaded, so we implement simple diffing + // logic using array_diff_key(). + foreach (array('css', 'js') as $type) { + // It is highly suspicious if $_POST['ajax_page_state'][$type] is empty, + // since the base page ought to have at least one JS file and one CSS file + // loaded. It probably indicates an error, and rather than making the page + // reload all of the files, instead we return no new files. + if (empty($_POST['ajax_page_state'][$type])) { + $items[$type] = array(); + } + else { + $function = 'drupal_add_' . $type; + $items[$type] = $function(); + drupal_alter($type, $items[$type]); + // @todo Inline CSS and JS items are indexed numerically. These can't be + // reliably diffed with array_diff_key(), since the number can change + // due to factors unrelated to the inline content, so for now, we strip + // the inline items from AJAX responses, and can add support for them + // when drupal_add_css() and drupal_add_js() are changed to using md5() + // or some other hash of the inline content. + foreach ($items[$type] as $key => $item) { + if (is_numeric($key)) { + unset($items[$type][$key]); + } + } + // Ensure that the page doesn't reload what it already has. + $items[$type] = array_diff_key($items[$type], $_POST['ajax_page_state'][$type]); + } + } + + // Render the HTML to load these files, and add AJAX commands to insert this + // HTML in the page. We pass TRUE as the $skip_alter argument to prevent the + // data from being altered again, as we already altered it above. + $styles = drupal_get_css($items['css'], TRUE); + $scripts_footer = drupal_get_js('footer', $items['js'], TRUE); + $scripts_header = drupal_get_js('header', $items['js'], TRUE); + + $extra_commands = array(); + if (!empty($styles)) { + $extra_commands[] = ajax_command_prepend('head', $styles); + } + if (!empty($scripts_header)) { + $extra_commands[] = ajax_command_prepend('head', $scripts_header); + } + if (!empty($scripts_footer)) { + $extra_commands[] = ajax_command_append('body', $scripts_footer); + } + if (!empty($extra_commands)) { + $commands = array_merge($extra_commands, $commands); + } + + $scripts = drupal_add_js(); if (!empty($scripts['settings'])) { - array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $scripts['settings']['data']))); + $settings = $scripts['settings']; + // Automatically extract any settings added via drupal_add_js() and make + // them the first command. + array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $settings['data']), TRUE)); } // Allow modules to alter any AJAX response. @@ -307,6 +362,39 @@ function ajax_form_callback() { } /** + * Theme callback for AJAX requests. + * + * Many different pages can invoke an AJAX request to system/ajax or another + * generic AJAX path. It is almost always desired for an AJAX response to be + * rendered using the same theme as the base page, because most themes are built + * with the assumption that they control the entire page, so if the CSS for two + * themes are both loaded for a given page, they may conflict with each other. + * For example, Bartik is Drupal's default theme, and Seven is Drupal's default + * administration theme. Depending on whether the "Use the administration theme + * when editing or creating content" checkbox is checked, the node edit form may + * be displayed in either theme, but the AJAX response to the Field module's + * "Add another item" button should be rendered using the same theme as the rest + * of the page. Therefore, system_menu() sets the 'theme callback' for + * 'system/ajax' to this function, and it is recommended that modules + * implementing other generic AJAX paths do the same. + */ +function ajax_base_page_theme() { + if (!empty($_POST['ajax_page_state']['theme']) && !empty($_POST['ajax_page_state']['theme_token'])) { + $theme = $_POST['ajax_page_state']['theme']; + $token = $_POST['ajax_page_state']['theme_token']; + + // Prevent a request forgery from giving a person access to a theme they + // shouldn't be otherwise allowed to see. However, since everyone is allowed + // to see the default theme, token validation isn't required for that, and + // bypassing it allows most use-cases to work even when accessed from the + // page cache. + if ($theme === variable_get('theme_default', 'bartik') || drupal_valid_token($token, $theme)) { + return $theme; + } + } +} + +/** * Package and send the result of a page callback to the browser as an AJAX response. * * @param $page_callback_result |