' . t('About') . ''; $output .= '
' . t('The Overlay module makes the administration pages on your site display in a JavaScript overlay of the page you were viewing when you clicked the administrative link, instead of replacing the page in your browser window. Use the close link on the overlay to return to the page you were viewing when you clicked the link. For more information, see the online handbook entry for Overlay module.', array('@overlay' => 'http://drupal.org/handbook/modules/overlay')) . '
'; return $output; } } /** * Implements hook_menu(). */ function overlay_menu() { $items['overlay-ajax/%'] = array( 'title' => '', '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_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); } 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('