'', 'page callback' => 'overlay_ajax_render_region', 'page arguments' => array(1), 'access arguments' => array('access overlay'), 'type' => MENU_CALLBACK, ); return $items; } /** * Implements hook_permission(). */ function overlay_permission() { return array( 'access overlay' => array( 'title' => t('Access the administrative overlay'), 'description' => t('View administrative pages in the overlay.'), ), ); } /** * Implements hook_init(). * * Determine whether the current page request is destined to appear in the * parent window or in the overlay window, and format the page accordingly. * * @see overlay_set_mode() */ function overlay_init() { // @todo: custom_theme does not exist anymore. global $custom_theme; // Only act if the user has access to administration pages. Other modules can // also enable the overlay directly for other uses of the JavaScript. if (user_access('access overlay')) { if (isset($_GET['render']) && $_GET['render'] == 'overlay') { // If this page shouldn't be rendered here, redirect to the parent. if (!path_is_admin($_GET['q'])) { overlay_close_dialog(); } // If system module did not switch the theme yet (i.e. this is not an // admin page, per se), we should switch the theme here. $admin_theme = variable_get('admin_theme', 0); if ($custom_theme != $admin_theme) { $custom_theme = $admin_theme; drupal_add_css(drupal_get_path('module', 'system') . '/admin.css'); } // Indicate that we are viewing an overlay child page. overlay_set_mode('child'); } else { // Otherwise add overlay parent code and our behavior. overlay_set_mode('parent'); } } } /** * Implements hook_exit(). * * When viewing an overlay child page, check if we need to trigger a refresh of * the supplemental regions of the overlay on the next page request. */ function overlay_exit() { // Check that we are in an overlay child page. Note that this should never // return TRUE on a cached page view, since the child mode is not set until // overlay_init() is called. if (overlay_get_mode() == 'child') { // Load any markup that was stored earlier in the page request, via calls // to overlay_store_rendered_content(). If none was stored, this is not a // page request where we expect any changes to the overlay supplemental // regions to have occurred, so we do not need to proceed any further. $original_markup = overlay_get_rendered_content(); if (!empty($original_markup)) { // Compare the original markup to the current markup that we get from // rendering each overlay supplemental region now. If they don't match, // something must have changed, so we request a refresh of that region // within the parent window on the next page request. foreach (overlay_supplemental_regions() as $region) { if (!isset($original_markup[$region]) || $original_markup[$region] != overlay_render_region($region)) { overlay_request_refresh($region); } } } } } /** * Implements hook_element_info_alter(). */ function overlay_element_info_alter(&$types) { foreach (array('submit', 'button', 'image_button', 'form') as $type) { $types[$type]['#after_build'][] = 'overlay_form_after_build'; } } /** * Implements hook_library(). */ function overlay_library() { $module_path = drupal_get_path('module', 'overlay'); // Overlay parent. $libraries['parent'] = array( 'title' => 'Overlay: Parent', 'website' => 'http://drupal.org/node/517688', 'version' => '1.0', 'js' => array( $module_path . '/overlay-parent.js' => array(), ), 'css' => array( $module_path . '/overlay-parent.css' => array(), ), 'dependencies' => array( array('system', 'ui.dialog'), array('system', 'jquery-bbq'), ), ); // Overlay child. $libraries['child'] = array( 'title' => 'Overlay: Child', 'website' => 'http://drupal.org/node/517688', 'version' => '1.0', 'js' => array( $module_path . '/overlay-child.js' => array(), ), 'dependencies' => array( array('system', 'ui'), ), ); return $libraries; } /** * Implements hook_form_alter(). * * For forms displayed in the overlay, add a hidden form field that lets us pass * the parent window's URL into the form. */ function overlay_form_alter(&$form, &$form_state, $form_id) { if (overlay_get_mode() == 'child') { $form['overlay_parent_url'] = array( '#type' => 'hidden', ); } } /** * Implements hook_drupal_goto_alter(). * * If the current page request is inside the overlay, add ?render=overlay to * the new path, so that it appears correctly inside the overlay. * * @see overlay_get_mode() */ function overlay_drupal_goto_alter(&$path, &$options, &$http_response_code) { if (overlay_get_mode() == 'child') { if (isset($options['query'])) { $options['query'] += array('render' => 'overlay'); } else { $options['query'] = array('render' => 'overlay'); } } } /** * Implements hook_batch_alter(). * * If the current page request is inside the overlay, add ?render=overlay to * the success callback URL, so that it appears correctly within the overlay. * * @see overlay_get_mode() */ function overlay_batch_alter(&$batch) { if (overlay_get_mode() == 'child') { if (isset($batch['url_options']['query'])) { $batch['url_options']['query']['render'] = 'overlay'; } else { $batch['url_options']['query'] = array('render' => 'overlay'); } } } /** * Implements hook_page_alter(). */ function overlay_page_alter(&$page) { // If we are limiting rendering to a subset of page regions, deny access to // all other regions so that they will not be processed. if ($regions_to_render = overlay_get_regions_to_render()) { $skipped_regions = array_diff(element_children($page), $regions_to_render); foreach ($skipped_regions as $skipped_region) { $page[$skipped_region]['#access'] = FALSE; } } } /** * Implements hook_block_info_alter(). */ function overlay_block_info_alter(&$blocks) { // If we are limiting rendering to a subset of page regions, hide all blocks // which appear in regions not on that list. Note that overlay_page_alter() // does a more comprehensive job of preventing unwanted regions from being // displayed (regardless of whether they contain blocks or not), but the // reason for duplicating effort here is performance; we do not even want // these blocks to be built if they are not going to be displayed. if ($regions_to_render = overlay_get_regions_to_render()) { foreach ($blocks as $bid => $block) { if (!in_array($block->region, $regions_to_render)) { unset($blocks[$bid]); } } } } /** * Implements hook_system_info_alter(). * * Add default regions for the overlay. */ function overlay_system_info_alter(&$info, $file, $type) { if ($type == 'theme') { $info['overlay_regions'][] = 'content'; $info['overlay_regions'][] = 'help'; } } /** * Preprocess template variables for html.tpl.php. * * If the current page request is inside the overlay, add appropriate classes * to the
element, and simplify the page title. * * @see overlay_get_mode() */ function overlay_preprocess_html(&$variables) { if (overlay_get_mode() == 'child') { // Add overlay class, so themes can react to being displayed in the overlay. $variables['classes_array'][] = 'overlay'; // Do not include site name or slogan in the overlay title. $variables['head_title'] = drupal_get_title(); } } /** * Preprocess template variables for page.tpl.php. * * Display breadcrumbs correctly inside the overlay. * * @see overlay_get_mode() */ function overlay_preprocess_page(&$variables) { if (overlay_get_mode() == 'child') { // Remove 'Home' from the breadcrumbs. $overlay_breadcrumb = drupal_get_breadcrumb(); array_shift($overlay_breadcrumb); $variables['breadcrumb'] = theme('breadcrumb', array('breadcrumb' => $overlay_breadcrumb)); } } /** * Preprocess template variables for toolbar.tpl.php. * * Adding the 'overlay-displace-top' class to the toolbar pushes the overlay * down, so it appears below the toolbar. */ function overlay_preprocess_toolbar(&$variables) { $variables['classes_array'][] = "overlay-displace-top"; } /** * Form after_build callback. * * After all hook_form_alter() implementations have been processed, we look at * the list of submit handlers and add our own at the end. The added handler * determines whether or not the user is redirected done at the end of form * processing, so that it's possible to close the overlay after submitting * a form. * * @see _form_builder_handle_input_element() * @see _form_builder_ie_cleanup() * @see form_execute_handlers() * @see form_builder() * @see overlay_form_submit() * * @ingroup forms */ function overlay_form_after_build($form, &$form_state) { if (isset($_GET['render']) && $_GET['render'] == 'overlay') { // Form API may have already captured submit handlers from the submitted // button before after_build callback is invoked. This may have been done // by _form_builder_handle_input_element(). If so, the list of submit // handlers is stored in the $form_state array, which is something we can // also alter from here, luckily. Rememeber: our goal here is to set // $form_state['redirect'] to FALSE if the API function // overlay_request_dialog_close() has been invoked. That's because we want // to tell the parent window to close the overlay. if (!empty($form_state['submit_handlers']) && !in_array('overlay_form_submit', $form_state['submit_handlers'])) { $form_state['submit_handlers'][] = 'overlay_form_submit'; } // If this element has submit handlers, then append our own. if (isset($form['#submit'])) { $form['#submit'][] = 'overlay_form_submit'; } } return $form; } /** * Generic form submit handler. * * When we are requested to close an overlay, we don't want Form API to * perform any redirection once the submitted form has been processed. * * When $form_state['redirect'] is set to FALSE, then Form API will simply * re-render the form with the values still in its fields. And this is all * we need to output the JavaScript that will tell the parent window to close * the child dialog. * * @see overlay_get_mode() * @ingroup forms */ function overlay_form_submit($form, &$form_state) { $settings = &drupal_static(__FUNCTION__); // Check if we have a request to close the overlay. $args = overlay_request_dialog_close(); // Close the overlay if the overlay module has been disabled if (!module_exists('overlay')) { $args = overlay_request_dialog_close(TRUE); } // If there is a form redirect to a non-admin page, close the overlay. if (isset($form_state['redirect'])) { // A destination set in the URL trumps $form_state['redirect']. if (isset($_GET['destination'])) { $url = $_GET['destination']; $url_settings = array(); } elseif (is_array($form_state['redirect'])) { $url = $form_state['redirect'][0]; $url_settings = $form_state['redirect'][1]; } else { $url = $form_state['redirect']; $url_settings = array(); } if (!path_is_admin($url)) { $args = overlay_request_dialog_close(TRUE); } } // If the overlay is to be closed, pass that information through JavaScript. if ($args !== FALSE) { if (!isset($settings)) { $settings = array( 'overlayChild' => array( 'closeOverlay' => TRUE, 'statusMessages' => theme('status_messages'), 'args' => $args, ), ); // Tell the child window to perform the redirection when requested to. if (!empty($form_state['redirect'])) { $settings['overlayChild']['redirect'] = url($url, $settings); } // If the redirect destination is the same as the parent window, just // close the overlay without redirecting the parent. if (url($form['overlay_parent_url']['#value']) == $settings['overlayChild']['redirect']) { unset($settings['overlayChild']['redirect']); } drupal_add_js($settings, array('type' => 'setting')); } // Tell FAPI to redraw the form without redirection after all submit // callbacks have been processed. $form_state['redirect'] = FALSE; } } /** * Get the current overlay mode. * * @see overlay_set_mode() */ function overlay_get_mode() { return overlay_set_mode(NULL); } /** * Set overlay mode and add proper JavaScript and styles to the page. * * @param $mode * To set the mode, pass in either 'parent' or 'child'. 'parent' is used in * the context of a parent window (a regular browser window), and JavaScript * is added so that administrative links in the parent window will open in * an overlay. 'child' is used in the context of the child overlay window (the * page actually appearing within the overlay iframe) and JavaScript and CSS * are added so that Drupal behaves nicely from within the overlay. * * This parameter is optional, and if omitted, the current mode will be * returned with no action taken. * * @return * The current mode, if any has been set, or NULL if no mode has been set. * * @ingroup overlay_api */ function overlay_set_mode($mode = NULL) { global $base_path; $overlay_mode = &drupal_static(__FUNCTION__); // Make sure external resources are not included more than once. Also return // the current mode, if no mode was specified. if (isset($overlay_mode) || !isset($mode)) { return $overlay_mode; } $overlay_mode = $mode; switch ($overlay_mode) { case 'parent': drupal_add_library('overlay', 'parent'); drupal_add_library('overlay', 'jquery-bbq'); // Allow modules to act upon overlay events. module_invoke_all('overlay_parent_initialize'); break; case 'child': drupal_add_library('overlay', 'child'); // Allow modules to act upon overlay events. module_invoke_all('overlay_child_initialize'); break; } return $overlay_mode; } /** * Implements hook_overlay_parent_initialize(). */ function overlay_overlay_parent_initialize() { // Let the client side know which paths are administrative. $paths = path_get_admin_paths(); foreach ($paths as &$type) { $type = str_replace('