Skip to content
overlay.module 29.6 KiB
Newer Older
<?php

/**
 * @file
 * Displays the Drupal administration interface in an overlay.
 */

use Drupal\Core\Template\RenderWrapper;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Drupal\Core\Session\AccountInterface;
/**
 * Implements hook_help().
 */
function overlay_help($path, $arg) {
  switch ($path) {
    case 'admin/help#overlay':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . 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 <a href="@overlay">Overlay module</a>.', array('@overlay' => 'http://drupal.org/documentation/modules/overlay')) . '</p>';
/**
 * Implements hook_admin_paths().
 */
function overlay_admin_paths() {
  $paths = array(
    // This is marked as an administrative path so that if it is visited from
    // within the overlay, the user will stay within the overlay while the
    // callback is being processed.
    'overlay/dismiss-message' => TRUE,
  );
  return $paths;
}

/**
 * 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_theme().
 */
function overlay_theme() {
  return array(
    'overlay' => array(
      'render element' => 'page',
      'template' => 'overlay',
    ),
    'overlay_disable_message' => array(
      'render element' => 'element',
      'template' => 'overlay-disable-message',
/**
 * Implements hook_field_extra_fields().
 */
function overlay_field_extra_fields() {
  $fields['user']['user']['form']['overlay_control'] = array(
    'label' => t('Administrative overlay'),
    'description' => t('Overlay module form element.'),
    'weight' => 4,
  );
  return $fields;
}

function overlay_form_user_form_alter(&$form, &$form_state) {
  $account = $form_state['controller']->getEntity();
  if ($account->hasPermission('access overlay')) {
    $account_data = \Drupal::service('user.data')->get('overlay', $account->id(), 'enabled');
      '#title' => t('Administrative overlay'),
      '#weight' => 4,
    );
    $form['overlay_control']['overlay'] = array(
      '#type' => 'checkbox',
      '#title' => t('Use the overlay for administrative pages.'),
      '#description' => t('Show administrative pages on top of the page you started from.'),
      '#default_value' => isset($account_data) ? $account_data : 1,
    $form['actions']['submit']['#submit'][] = 'overlay_user_profile_form_submit';
 * Submit callback for the user profile form to save the overlay page setting.
function overlay_user_profile_form_submit($form, &$form_state) {
  $account = $form_state['controller']->getEntity();
  if ($account->id() && isset($form_state['values']['overlay'])) {
    \Drupal::service('user.data')->set('overlay', $account->id(), 'enabled', (int) $form_state['values']['overlay']);
 * Implements hook_library_info().
function overlay_library_info() {
  $module_path = drupal_get_path('module', 'overlay');

  // Overlay parent.
  $libraries['drupal.overlay.parent'] = array(
    'website' => 'http://drupal.org/documentation/modules/overlay',
    'version' => '1.0',
    'js' => array(
      $module_path . '/overlay-parent.js' => array(),
    ),
    'css' => array(
      $module_path . '/css/overlay-parent.css' => array(),
      array('system', 'jquery'),
      array('system', 'drupal'),
      array('system', 'drupalSettings'),
      array('system', 'drupal.displace'),
      array('system', 'drupal.tabbingmanager'),
      array('system', 'drupal.announce'),
  $libraries['drupal.overlay.child'] = array(
    'website' => 'http://drupal.org/documentation/modules/overlay',
    'version' => '1.0',
    'js' => array(
      $module_path . '/overlay-child.js' => array(),
    ),
      $module_path . '/css/overlay-child.css' => array(),
    'dependencies' => array(
      array('system', 'jquery'),
      array('system', 'drupal'),
      array('system', 'drupalSettings'),
  );

  return $libraries;
}

/**
 * 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;
    }
  }
  $mode = overlay_get_mode();
  if ($mode == 'child') {
    // Add the overlay wrapper before the html wrapper.
    array_unshift($page['#theme_wrappers'], 'overlay');
  }
  elseif ($mode == 'parent' && ($message = overlay_disable_message())) {
    $page['page_top']['disable_overlay'] = $message;
  }
}

/**
 * Returns a renderable array representing a message for disabling the overlay.
 *
 * If the current user can access the overlay and has not previously indicated
 * that this message should be dismissed, this function returns a message
 * containing a link to disable the overlay. Nothing is returned for anonymous
 * users, because the links control per-user settings. Because some screen
 * readers are unable to properly read overlay contents, site builders are
 * discouraged from granting the "access overlay" permission to the anonymous
 * role.
 *
 * @see http://drupal.org/node/890284
  if ($user->isAnonymous() || !$user->hasPermission('access overlay')) {
  $user_data = \Drupal::service('user.data')->get('overlay', $user->id());
  if (empty($user_data['message_dismissed']) && (!isset($user_data['enabled']) || $user_data['enabled'])) {
    $build = array(
      '#theme' => 'overlay_disable_message',
      '#weight' => -99,
      // Link to the user's profile page, where the overlay can be disabled.
      'profile_link' => array(
        '#type' => 'link',
        '#title' => t('If you have problems accessing administrative pages on this site, disable the overlay on your profile page.'),
        '#options' => array(
          'query' => drupal_get_destination(),
          'fragment' => 'edit-overlay-control',
          'attributes' => array(
            'id' => 'overlay-profile-link',
            // Prevent the target page from being opened in the overlay.
            'class' => array('overlay-exclude'),
          ),
        ),
      ),
      // Link to a menu callback that allows this message to be permanently
      // dismissed for the current user.
      'dismiss_message_link' => array(
        '#type' => 'link',
        '#title' => t('Dismiss this message.'),
        '#href' => 'overlay/dismiss-message',
        '#options' => array(
          'query' => drupal_get_destination() + array(
            // Add a token to protect against cross-site request forgeries.
            'token' => drupal_get_token('overlay'),
          ),
          'attributes' => array(
            'id' => 'overlay-dismiss-message',
            // If this message is being displayed outside the overlay, prevent
            // this link from opening the overlay.
            'class' => (overlay_get_mode() == 'parent') ? array('overlay-exclude') : array(),
          ),
        ),
      )
    );
  }

  return $build;
}

/**
 * Prepares variables for overlay disable message templates.
 * Default template: overlay-disable-message.html.twig.
 *
 * @param array $variables
 *   An associative array with an 'element' element, which itself is an
 *   associative array containing:
 *   - profile_link: The link to this user's account.
 *   - dismiss_message_link: The link to dismiss the overlay.
function template_preprocess_overlay_disable_message(&$variables) {
  $element = $variables['element'];

  // Add CSS classes to hide the links from most sighted users, while keeping
  // them accessible to screen-reader users and keyboard-only users. To assist
  // screen-reader users, this message appears in both the parent and child
  // documents, but only the one in the child document is part of the tab order.
  foreach (array('profile_link', 'dismiss_message_link') as $key) {
    $element[$key]['#options']['attributes']['class'][] = 'visually-hidden';
      $element[$key]['#options']['attributes']['class'][] = 'focusable';
  $variables['profile_link'] = $element['profile_link'];
  $variables['dismiss_link'] = $element['dismiss_message_link'];
function overlay_block_access(Block $block, $operation, AccountInterface $account, $langcode) {
  // 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()) {
    if (!in_array($block->get('region'), $regions_to_render)) {
    }
  }
}

/**
 * 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';
  }
}

/**
 * Implements hook_preprocess_HOOK() for HTML document templates.
 *
 * If the current page request is inside the overlay, add appropriate classes
 * to the <body> 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['attributes']['class'][] = 'overlay';
 * Implements hook_preprocess_HOOK() for maintenance page templates.
 *
 * If the current page request is inside the overlay, add appropriate classes
 * to the <body> element, and simplify the page title.
 */
function overlay_preprocess_maintenance_page(&$variables) {
  overlay_preprocess_html($variables);
}

 * Prepares variables for overlay templates.
 *
 * Default template: overlay.html.twig.
 *
 * If the current page request is inside the overlay, add appropriate classes
 * to the <body> element, and simplify the page title.
 * @param array $variables
 *   An associative array containing:
 *   - page: A render element representing the page.
 */
function template_preprocess_overlay(&$variables) {
  $variables['tabs'] = menu_primary_local_tasks();

  if (isset($variables['page']['#title'])) {
    $variables['title'] = $variables['page']['#title'];
  }
  else {
    $variables['title'] = new RenderWrapper('drupal_get_title');
  }
  $variables['disable_overlay'] = overlay_disable_message();
  // Add attributes for the overlay container.
  $variables['attributes']['id'] = 'overlay';
  $variables['attributes']['class'][] = 'overlay';
  // Add attributes for the overlay title.
  $variables['title_attributes']['id'] = 'overlay-title';
  // Add attributes for the overlay content.
  $variables['content_attributes']['id'] = 'overlay-content';
  $variables['content_attributes']['class'][] = 'clearfix';
 * Implements hook_preprocess_HOOK() for page templates.
 * If the current page request is inside the overlay, hide the tabs.
 *
 * @see overlay_get_mode()
 */
function overlay_preprocess_page(&$variables) {
  if (overlay_get_mode() == 'child') {
    unset($variables['tabs']['#primary']);
 *
 * This function is used to print out a bare minimum empty page which still has
 * the scripts and styles necessary in order to trigger the overlay to close.
 *
 * It can be used to prevent a page request which closes the overlay (for
 * example, a form submission) from being fully re-rendered before the overlay
 * is closed, thereby allowing the dialog to be closed faster and with less
 * interruption, and also allowing the display of messages to be deferred to
 * the parent window (rather than displaying them in the child window, which
 * will close before the user has had a chance to read them).
 *
 * @return \Symfony\Component\HttpFoundation\Response
 *   A Response object.
 */
function overlay_deliver_empty_page() {
  $empty_page = '<html><head><title></title>' . drupal_get_css() . drupal_get_js() . '</head><body class="overlay"></body></html>';
  return new Response($empty_page);
 *
 * @see overlay_set_mode()
 */
function overlay_get_mode() {
  return overlay_set_mode(NULL);
}

/**
 * Sets the overlay mode and adds proper JavaScript and styles to the page.
 * Note that since setting the overlay mode triggers a variety of behaviors
 * (including hooks being invoked), it can only be done once per page request.
 * Therefore, the first call to this function which passes along a value of the
 * $mode parameter controls the overlay mode that will be used.
 * @param $mode
 *   To set the mode, pass in one of the following values:
 *   - 'parent': This is used in the context of a parent window (a regular
 *     browser window). If set, JavaScript is added so that administrative
 *     links in the parent window will open in an overlay.
 *   - 'child': This is used in the context of the child overlay window (the
 *     page actually appearing within the overlay iframe). If set, JavaScript
 *     and CSS are added so that Drupal behaves nicely from within the overlay.
 *   - 'none': This is used to avoid adding any overlay-related code to the
 *     page at all. Modules can set this to explicitly prevent the overlay from
 *     being used. For example, since the overlay module itself sets the mode
 *     to 'parent' or 'child' in the overlay event subscriber when certain
 *     conditions are met, other modules which want to override that behavior
 *     can do so by setting the mode to 'none' earlier in the page request -
 *     e.g., in their own event subscribers, if they have a higher priority.
 *   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
 * @see \Drupal\overlay\EventSubscriber\OverlaySubscriber::onRequest()
 */
function overlay_set_mode($mode = NULL) {
  // We're not using drupal_static() here since the static cache is reset in
  // drupal_flush_all_caches(); this could lead to the loss of the overlay when
  // submitting the admin/modules form, for instance.
  static $overlay_mode;

  // 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', 'drupal.overlay.parent');

      // Allow modules to act upon overlay events.
      \Drupal::moduleHandler()->invokeAll('overlay_parent_initialize');
      drupal_add_library('overlay', 'drupal.overlay.child');

      // Allow modules to act upon overlay events.
      \Drupal::moduleHandler()->invokeAll('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('<front>', \Drupal::config('system.site')->get('page.front'), $type);
  }
  drupal_add_js(array('overlay' => array('paths' => $paths)), 'setting');
catch's avatar
catch committed
  if (module_exists('language')) {
    if (\Drupal::config('language.negotiation')->get('url.source') == LANGUAGE_NEGOTIATION_URL_PREFIX) {
      // Skip the empty string indicating the default language. We always accept
      // paths without a prefix.
      $path_prefixes = language_negotiation_url_prefixes();
      $path_prefixes = array_values(array_filter($path_prefixes));
    }
  }
  drupal_add_js(array('overlay' => array('pathPrefixes' => $path_prefixes)), 'setting');
  // Pass along the Ajax callback for rerendering sections of the parent window.
  drupal_add_js(array('overlay' => array('ajaxCallback' => 'overlay-ajax')), 'setting');
}

/**
 * Implements hook_overlay_child_initialize().
 */
function overlay_overlay_child_initialize() {
  // Check if the parent window needs to refresh any page regions on this page
  // request.
  // If this is a POST request, or a GET request with a token parameter, we
  // have an indication that something in the supplemental regions of the
  // overlay might change during the current page request. We therefore store
  // the initial rendered content of those regions here, so that we can compare
  // it to the same content rendered in OverlaySubscriber::onResponse(),
  // at the end of the page request. This allows us to check if anything
  // actually did change, and, if so, trigger an immediate Ajax refresh
  // of the parent window.
  $token = \Drupal::request()->query->get('token');
  $post = \Drupal::request()->request->count();
    foreach (overlay_supplemental_regions() as $region) {
      overlay_store_rendered_content($region, overlay_render_region($region));
    }
    // In addition, notify the parent window that when the overlay closes,
    // the entire parent window should be refreshed.
    overlay_request_page_refresh();
  }
  // Indicate that when the main page rendering occurs later in the page
  // request, only the regions that appear within the overlay should be
  // rendered.
  overlay_set_regions_to_render(overlay_regions());
}

/**
 * Immediately returns HTML to to the browser and closes the overlay.
 *   (optional) The path that should open in the parent window after the
 *   overlay closes. If not set, no redirect will be performed on the parent
 *   window.
 * @param $redirect_options
 *   (optional) An associative array of options to use when generating the
 *   redirect URL.
 * @return \Symfony\Component\HttpFoundation\Response
 *   A Response object.
 *
 * @todo This function should only request that the overlay close when the page
 *   is displayed (as it did in Drupal 7), not immediately end the request.
function overlay_close_dialog($redirect = NULL, $redirect_options = array()) {
  $settings = array(
    'overlayChild' => array(
      'closeOverlay' => TRUE,
    ),
  );

  // Tell the child window to perform the redirection when requested to.
  if (isset($redirect)) {
    $settings['overlayChild']['redirect'] = url($redirect, $redirect_options);
  }

  drupal_add_js($settings, array('type' => 'setting'));

  // Since we are closing the overlay as soon as the page is displayed, we do
  // not want to show any of the page's actual content.
  return overlay_deliver_empty_page();
}

/**
 * Returns a list of page regions that appear in the overlay.
 *
 * Overlay regions correspond to the entire contents of the overlay child
 * window and are refreshed each time a new page request is made within the
 * overlay.
 *
 * @return
 *   An array of region names that correspond to those which appear in the
 *   overlay, within the theme that is being used to display the current page.
 *
 * @see overlay_supplemental_regions()
 */
function overlay_regions() {
  return _overlay_region_list('overlay_regions');
}

/**
 * Returns a list of supplemental page regions for the overlay.
 *
 * Supplemental overlay regions are those which are technically part of the
 * parent window, but appear to the user as being related to the overlay
 * (usually because they are displayed next to, rather than underneath, the
 * main overlay regions) and therefore need to be dynamically refreshed if any
 * administrative actions taken within the overlay change their contents.
 *
 * An example of a typical overlay supplemental region would be the 'page_top'
 * region, in the case where a toolbar is being displayed there.
 *
 * @return
 *   An array of region names that correspond to supplemental overlay regions,
 *   within the theme that is being used to display the current page.
 *
 * @see overlay_regions()
 */
function overlay_supplemental_regions() {
  return _overlay_region_list('overlay_supplemental_regions');
}

/**
 * Returns a list of page regions related to the overlay.
 *
 * @param $type
 *   The type of regions to return. This can either be 'overlay_regions' or
 *   'overlay_supplemental_regions'.
 *
 * @return
 *   An array of region names of the given type, within the theme that is being
 *   used to display the current page.
 *
 * @see overlay_regions()
 * @see overlay_supplemental_regions()
 */
function _overlay_region_list($type) {
  // Obtain the current theme. We need to first make sure the theme system is
  // initialized, since this function can be called early in the page request.
  drupal_theme_initialize();
  $themes = list_themes();
  $theme = $themes[$GLOBALS['theme']];
  // Return the list of regions stored within the theme's info array, or an
  // empty array if no regions of the appropriate type are defined.
  return !empty($theme->info[$type]) ? $theme->info[$type] : array();
}

/**
 * Returns a list of page regions that rendering should be limited to.
 *
 * @return
 *   An array containing the names of the regions that will be rendered when
 *   drupal_render_page() is called. If empty, then no limits will be imposed,
 *   and all regions of the page will be rendered.
 *
 * @see overlay_page_alter()
 * @see overlay_set_regions_to_render()
 */
function overlay_get_regions_to_render() {
  return overlay_set_regions_to_render();
}

/**
 * Sets the regions of the page that rendering will be limited to.
 *
 * @param $regions
 *   (Optional) An array containing the names of the regions that should be
 *   rendered when drupal_render_page() is called. Pass in an empty array to
 *   remove all limits and cause drupal_render_page() to render all page
 *   regions (the default behavior). If this parameter is omitted, no change
 *   will be made to the current list of regions to render.
 *
 * @return
 *   The current list of regions to render, or an empty array if the regions
 *   are not being limited.
 *
 * @see overlay_page_alter()
 * @see overlay_get_regions_to_render()
 */
function overlay_set_regions_to_render($regions = NULL) {
  $regions_to_render = &drupal_static(__FUNCTION__, array());
  if (isset($regions)) {
    $regions_to_render = $regions;
  }
  return $regions_to_render;
}

/**
 * Renders an individual page region.
 *
 * This function is primarily intended to be used for checking the content of
 * supplemental overlay regions (e.g., a region containing a toolbar). Passing
 * in a region that is intended to display the main page content is not
 * supported; the region will be rendered by this function, but the main page
 * content will not appear in it. In addition, although this function returns
 * the rendered HTML for the provided region, it does not place it on the final
 * page, nor add any of its associated JavaScript or CSS to the page.
 *
 * @param $region
 *   The name of the page region that should be rendered.
 *
 * @return
 *   The rendered HTML of the provided region.
 */
function overlay_render_region($region) {
  // Indicate the region that we will be rendering, so that other regions will
  // be hidden by overlay_page_alter() and overlay_block_access().
  overlay_set_regions_to_render(array($region));
  // Do what is necessary to force drupal_render_page() to only display HTML
  // from the requested region. Specifically, declare that the main page
  // content does not need to automatically be added to the page, and pass in
  // a page array that has all theme functions removed (so that overall HTML
  // for the page will not be added either).
  $system_main_content_added = &drupal_static('system_main_content_added');
  $system_main_content_added = TRUE;
  $page = array(
    '#type' => 'page',
    '#theme' => NULL,
    '#theme_wrappers' => array(),
  );
  // Render the region, but do not cache any JavaScript or CSS associated with
  // it. This region might not be included the next time drupal_render_page()
  // is called, and we do not want its JavaScript or CSS to erroneously appear
  // on the final rendered page.
  $original_js = drupal_add_js();
  $original_css = drupal_add_css();
  $original_libraries = drupal_static('drupal_add_library');
  $js = &drupal_static('drupal_add_js');
  $css = &drupal_static('drupal_add_css');
  $libraries = &drupal_static('drupal_add_library');
  $markup = drupal_render_page($page);
  $js = $original_js;
  $css = $original_css;
  // Indicate that the main page content has not, in fact, been displayed, so
  // that future calls to drupal_render_page() will be able to render it
  // correctly.
  $system_main_content_added = FALSE;
  // Restore the original behavior of rendering all regions for the next time
  // drupal_render_page() is called.
  overlay_set_regions_to_render(array());
  return $markup;
}

/**
 * Returns any rendered content that was stored earlier in the page request.
 *
 * @return
 *   An array of all rendered HTML that was stored earlier in the page request,
 *   keyed by the identifier with which it was stored. If no content was
 *   stored, an empty array is returned.
 *
 * @see overlay_store_rendered_content()
 */
function overlay_get_rendered_content() {
  return overlay_store_rendered_content();
}

/**
 * Stores strings representing rendered HTML content.
 *
 * This function is used to keep a static cache of rendered content that can be
 * referred to later in the page request.
 *
 * @param $id
 *   (Optional) An identifier for the content which is being stored, which will
 *   be used as an array key in the returned array. If omitted, no change will
 *   be made to the current stored data.
 * @param $content
 *   (Optional) A string representing the rendered data to store. This only has
 *   an effect if $id is also provided.
 *
 * @return
 *   An array representing all data that is currently being stored, or an empty
 *   array if there is none.
 *
 * @see overlay_get_rendered_content()
 */
function overlay_store_rendered_content($id = NULL, $content = NULL) {
  $rendered_content = &drupal_static(__FUNCTION__, array());
  if (isset($id)) {
    $rendered_content[$id] = $content;
  }
  return $rendered_content;
}

/**
 * Requests that the parent window refreshes a particular page region.
 *
 * @param $region
 *   The name of the page region to refresh. The parent window will trigger a
 *   refresh of this region on the next page load.
 *
 * @see Drupal.overlay.refreshRegions()
 */
function overlay_request_refresh($region) {
  $class = drupal_html_class("region-$region");
  $_SESSION['overlay_regions_to_refresh'][] = array($class => $region);
}

/**
 * Requests that the entire parent window is reloaded when the overlay closes.
 * @see overlay_trigger_refresh()
 */
function overlay_request_page_refresh() {
  $_SESSION['overlay_refresh_parent'] = TRUE;
}

/**
 * Checks if the parent window needs to be refreshed on this page load.
 *
 * If the previous page load requested that any page regions be refreshed, or
 * if it requested that the entire page be refreshed when the overlay closes,
 * pass that request via JavaScript to the child window, so it can in turn pass
 * the request to the parent window.
 * @see Drupal.overlay.refreshRegions()
 */
  if (!empty($_SESSION['overlay_regions_to_refresh'])) {
    $settings = array(
      'overlayChild' => array(
        'refreshRegions' => $_SESSION['overlay_regions_to_refresh'],
      ),
    );
    drupal_add_js($settings, array('type' => 'setting'));
    unset($_SESSION['overlay_regions_to_refresh']);
  }
  if (!empty($_SESSION['overlay_refresh_parent'])) {
    drupal_add_js(array('overlayChild' => array('refreshPage' => TRUE)), array('type' => 'setting'));
    unset($_SESSION['overlay_refresh_parent']);
  }