Drupal PHP Cross Reference Content Management Systems

Source: /modules/overlay/overlay.module - 1006 lines - 35816 bytes - Summary - Text - Print

   1  <?php
   2  
   3  /**
   4   * @file
   5   * Displays the Drupal administration interface in an overlay.
   6   */
   7  
   8  /**
   9   * Implements hook_help().
  10   */
  11  function overlay_help($path, $arg) {
  12    switch ($path) {
  13      case 'admin/help#overlay':
  14        $output = '';
  15        $output .= '<h3>' . t('About') . '</h3>';
  16        $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>';
  17        return $output;
  18    }
  19  }
  20  
  21  /**
  22   * Implements hook_menu().
  23   */
  24  function overlay_menu() {
  25    $items['overlay-ajax/%'] = array(
  26      'title' => '',
  27      'page callback' => 'overlay_ajax_render_region',
  28      'page arguments' => array(1),
  29      'access arguments' => array('access overlay'),
  30      'type' => MENU_CALLBACK,
  31    );
  32    $items['overlay/dismiss-message'] = array(
  33      'title' => '',
  34      'page callback' => 'overlay_user_dismiss_message',
  35      'access arguments' => array('access overlay'),
  36      'type' => MENU_CALLBACK,
  37    );
  38    return $items;
  39  }
  40  
  41  /**
  42   * Implements hook_admin_paths().
  43   */
  44  function overlay_admin_paths() {
  45    $paths = array(
  46      // This is marked as an administrative path so that if it is visited from
  47      // within the overlay, the user will stay within the overlay while the
  48      // callback is being processed.
  49      'overlay/dismiss-message' => TRUE,
  50    );
  51    return $paths;
  52  }
  53  
  54  /**
  55   * Implements hook_permission().
  56   */
  57  function overlay_permission() {
  58    return array(
  59      'access overlay' => array(
  60        'title' => t('Access the administrative overlay'),
  61        'description' => t('View administrative pages in the overlay.'),
  62      ),
  63    );
  64  }
  65  
  66  /**
  67   * Implements hook_theme().
  68   */
  69  function overlay_theme() {
  70    return array(
  71      'overlay' => array(
  72        'render element' => 'page',
  73        'template' => 'overlay',
  74      ),
  75      'overlay_disable_message' => array(
  76        'render element' => 'element',
  77      ),
  78    );
  79  }
  80  
  81  /**
  82   * Implements hook_form_FORM_ID_alter().
  83   */
  84  function overlay_form_user_profile_form_alter(&$form, &$form_state) {
  85    if ($form['#user_category'] == 'account') {
  86      $account = $form['#user'];
  87      if (user_access('access overlay', $account)) {
  88        $form['overlay_control'] = array(
  89          '#type' => 'fieldset',
  90          '#title' => t('Administrative overlay'),
  91          '#weight' => 4,
  92          '#collapsible' => TRUE,
  93        );
  94  
  95        $form['overlay_control']['overlay'] = array(
  96          '#type' => 'checkbox',
  97          '#title' => t('Use the overlay for administrative pages.'),
  98          '#description' => t('Show administrative pages on top of the page you started from.'),
  99          '#default_value' => isset($account->data['overlay']) ? $account->data['overlay'] : 1,
 100        );
 101      }
 102    }
 103  }
 104  
 105  /**
 106   * Implements hook_user_presave().
 107   */
 108  function overlay_user_presave(&$edit, $account, $category) {
 109    if (isset($edit['overlay'])) {
 110      $edit['data']['overlay'] = $edit['overlay'];
 111    }
 112  }
 113  
 114  /**
 115   * Implements hook_init().
 116   *
 117   * Determine whether the current page request is destined to appear in the
 118   * parent window or in the overlay window, and format the page accordingly.
 119   *
 120   * @see overlay_set_mode()
 121   */
 122  function overlay_init() {
 123    global $user;
 124  
 125    $mode = overlay_get_mode();
 126  
 127    // Only act if the user has access to the overlay and a mode was not already
 128    // set. Other modules can also enable the overlay directly for other uses.
 129    $use_overlay = !isset($user->data['overlay']) || $user->data['overlay'];
 130    if (empty($mode) && user_access('access overlay') && $use_overlay) {
 131      $current_path = current_path();
 132      // After overlay is enabled on the modules page, redirect to
 133      // <front>#overlay=admin/modules to actually enable the overlay.
 134      if (isset($_SESSION['overlay_enable_redirect']) && $_SESSION['overlay_enable_redirect']) {
 135        unset($_SESSION['overlay_enable_redirect']);
 136        drupal_goto('<front>', array('fragment' => 'overlay=' . $current_path));
 137      }
 138  
 139      if (isset($_GET['render']) && $_GET['render'] == 'overlay') {
 140        // If a previous page requested that we close the overlay, close it and
 141        // redirect to the final destination.
 142        if (isset($_SESSION['overlay_close_dialog'])) {
 143          call_user_func_array('overlay_close_dialog', $_SESSION['overlay_close_dialog']);
 144          unset($_SESSION['overlay_close_dialog']);
 145        }
 146        // If this page shouldn't be rendered inside the overlay, redirect to the
 147        // parent.
 148        elseif (!path_is_admin($current_path)) {
 149          overlay_close_dialog($current_path, array('query' => drupal_get_query_parameters(NULL, array('q', 'render'))));
 150        }
 151  
 152        // Indicate that we are viewing an overlay child page.
 153        overlay_set_mode('child');
 154  
 155        // Unset the render parameter to avoid it being included in URLs on the page.
 156        unset($_GET['render']);
 157      }
 158      // Do not enable the overlay if we already are on an admin page.
 159      elseif (!path_is_admin($current_path)) {
 160        // Otherwise add overlay parent code and our behavior.
 161        overlay_set_mode('parent');
 162      }
 163    }
 164  }
 165  
 166  /**
 167   * Implements hook_exit().
 168   *
 169   * When viewing an overlay child page, check if we need to trigger a refresh of
 170   * the supplemental regions of the overlay on the next page request.
 171   */
 172  function overlay_exit() {
 173    // Check that we are in an overlay child page. Note that this should never
 174    // return TRUE on a cached page view, since the child mode is not set until
 175    // overlay_init() is called.
 176    if (overlay_get_mode() == 'child') {
 177      // Load any markup that was stored earlier in the page request, via calls
 178      // to overlay_store_rendered_content(). If none was stored, this is not a
 179      // page request where we expect any changes to the overlay supplemental
 180      // regions to have occurred, so we do not need to proceed any further.
 181      $original_markup = overlay_get_rendered_content();
 182      if (!empty($original_markup)) {
 183        // Compare the original markup to the current markup that we get from
 184        // rendering each overlay supplemental region now. If they don't match,
 185        // something must have changed, so we request a refresh of that region
 186        // within the parent window on the next page request.
 187        foreach (overlay_supplemental_regions() as $region) {
 188          if (!isset($original_markup[$region]) || $original_markup[$region] != overlay_render_region($region)) {
 189            overlay_request_refresh($region);
 190          }
 191        }
 192      }
 193    }
 194  }
 195  
 196  /**
 197   * Implements hook_library().
 198   */
 199  function overlay_library() {
 200    $module_path = drupal_get_path('module', 'overlay');
 201  
 202    // Overlay parent.
 203    $libraries['parent'] = array(
 204      'title' => 'Overlay: Parent',
 205      'website' => 'http://drupal.org/documentation/modules/overlay',
 206      'version' => '1.0',
 207      'js' => array(
 208        $module_path . '/overlay-parent.js' => array(),
 209      ),
 210      'css' => array(
 211        $module_path . '/overlay-parent.css' => array(),
 212      ),
 213      'dependencies' => array(
 214        array('system', 'ui'),
 215        array('system', 'jquery.bbq'),
 216      ),
 217    );
 218    // Overlay child.
 219    $libraries['child'] = array(
 220      'title' => 'Overlay: Child',
 221      'website' => 'http://drupal.org/documentation/modules/overlay',
 222      'version' => '1.0',
 223      'js' => array(
 224        $module_path . '/overlay-child.js' => array(),
 225      ),
 226      'css' => array(
 227        $module_path . '/overlay-child.css' => array(),
 228      ),
 229    );
 230  
 231    return $libraries;
 232  }
 233  
 234  /**
 235   * Implements hook_drupal_goto_alter().
 236   */
 237  function overlay_drupal_goto_alter(&$path, &$options, &$http_response_code) {
 238    if (overlay_get_mode() == 'child') {
 239      // The authorize.php script bootstraps Drupal to a very low level, where
 240      // the PHP code that is necessary to close the overlay properly will not be
 241      // loaded. Therefore, if we are redirecting to authorize.php inside the
 242      // overlay, instead redirect back to the current page with instructions to
 243      // close the overlay there before redirecting to the final destination; see
 244      // overlay_init().
 245      if ($path == system_authorized_get_url() || $path == system_authorized_batch_processing_url()) {
 246        $_SESSION['overlay_close_dialog'] = array($path, $options);
 247        $path = current_path();
 248        $options = drupal_get_query_parameters();
 249      }
 250  
 251      // If the current page request is inside the overlay, add ?render=overlay
 252      // to the new path, so that it appears correctly inside the overlay.
 253      if (isset($options['query'])) {
 254        $options['query'] += array('render' => 'overlay');
 255      }
 256      else {
 257        $options['query'] = array('render' => 'overlay');
 258      }
 259    }
 260  }
 261  
 262  /**
 263   * Implements hook_batch_alter().
 264   *
 265   * If the current page request is inside the overlay, add ?render=overlay to
 266   * the success callback URL, so that it appears correctly within the overlay.
 267   *
 268   * @see overlay_get_mode()
 269   */
 270  function overlay_batch_alter(&$batch) {
 271    if (overlay_get_mode() == 'child') {
 272      if (isset($batch['url_options']['query'])) {
 273        $batch['url_options']['query']['render'] = 'overlay';
 274      }
 275      else {
 276        $batch['url_options']['query'] = array('render' => 'overlay');
 277      }
 278    }
 279  }
 280  
 281  /**
 282   * Implements hook_page_alter().
 283   */
 284  function overlay_page_alter(&$page) {
 285    // If we are limiting rendering to a subset of page regions, deny access to
 286    // all other regions so that they will not be processed.
 287    if ($regions_to_render = overlay_get_regions_to_render()) {
 288      $skipped_regions = array_diff(element_children($page), $regions_to_render);
 289      foreach ($skipped_regions as $skipped_region) {
 290        $page[$skipped_region]['#access'] = FALSE;
 291      }
 292    }
 293  
 294    $mode = overlay_get_mode();
 295    if ($mode == 'child') {
 296      // Add the overlay wrapper before the html wrapper.
 297      array_unshift($page['#theme_wrappers'], 'overlay');
 298    }
 299    elseif ($mode == 'parent' && ($message = overlay_disable_message())) {
 300      $page['page_top']['disable_overlay'] = $message;
 301    }
 302  }
 303  
 304  /**
 305   * Page callback: Dismisses the overlay accessibility message for this user.
 306   *
 307   * @return
 308   *   A render array for a page containing a list of content.
 309   */
 310  function overlay_user_dismiss_message() {
 311    global $user;
 312    // It's unlikely, but possible that "access overlay" permission is granted to
 313    // the anonymous role. In this case, we do not display the message to disable
 314    // the overlay, so there is nothing to dismiss. Also, protect against
 315    // cross-site request forgeries by validating a token.
 316    if (empty($user->uid) || !isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'overlay')) {
 317      return MENU_ACCESS_DENIED;
 318    }
 319    else {
 320      user_save(user_load($user->uid), array('data' => array('overlay_message_dismissed' => 1)));
 321      drupal_set_message(t('The message has been dismissed. You can change your overlay settings at any time by visiting your profile page.'));
 322      // Destination is normally given. Go to the user profile as a fallback.
 323      drupal_goto('user/' . $user->uid . '/edit');
 324    }
 325  }
 326  
 327  /**
 328   * Returns a renderable array representing a message for disabling the overlay.
 329   *
 330   * If the current user can access the overlay and has not previously indicated
 331   * that this message should be dismissed, this function returns a message
 332   * containing a link to disable the overlay. Nothing is returned for anonymous
 333   * users, because the links control per-user settings. Because some screen
 334   * readers are unable to properly read overlay contents, site builders are
 335   * discouraged from granting the "access overlay" permission to the anonymous
 336   * role.
 337   *
 338   * @see http://drupal.org/node/890284
 339   */
 340  function overlay_disable_message() {
 341    global $user;
 342  
 343    if (!empty($user->uid) && empty($user->data['overlay_message_dismissed']) && (!isset($user->data['overlay']) || $user->data['overlay']) && user_access('access overlay')) {
 344      $build = array(
 345        '#theme' => 'overlay_disable_message',
 346        '#weight' => -99,
 347        // Link to the user's profile page, where the overlay can be disabled.
 348        'profile_link' => array(
 349          '#type' => 'link',
 350          '#title' => t('If you have problems accessing administrative pages on this site, disable the overlay on your profile page.'),
 351          '#href' => 'user/' . $user->uid . '/edit',
 352          '#options' => array(
 353            'query' => drupal_get_destination(),
 354            'fragment' => 'edit-overlay-control',
 355            'attributes' => array(
 356              'id' => 'overlay-profile-link',
 357              // Prevent the target page from being opened in the overlay.
 358              'class' => array('overlay-exclude'),
 359            ),
 360          ),
 361        ),
 362        // Link to a menu callback that allows this message to be permanently
 363        // dismissed for the current user.
 364        'dismiss_message_link' => array(
 365          '#type' => 'link',
 366          '#title' => t('Dismiss this message.'),
 367          '#href' => 'overlay/dismiss-message',
 368          '#options' => array(
 369            'query' => drupal_get_destination() + array(
 370              // Add a token to protect against cross-site request forgeries.
 371              'token' => drupal_get_token('overlay'),
 372            ),
 373            'attributes' => array(
 374              'id' => 'overlay-dismiss-message',
 375              // If this message is being displayed outside the overlay, prevent
 376              // this link from opening the overlay.
 377              'class' => (overlay_get_mode() == 'parent') ? array('overlay-exclude') : array(),
 378            ),
 379          ),
 380        )
 381      );
 382    }
 383    else {
 384      $build = array();
 385    }
 386  
 387    return $build;
 388  }
 389  
 390  /**
 391   * Returns the HTML for the message about how to disable the overlay.
 392   *
 393   * @param $variables
 394   *   An associative array with an 'element' element, which itself is an
 395   *   associative array containing:
 396   *   - profile_link: The link to this user's account.
 397   *   - dismiss_message_link: The link to dismiss the overlay.
 398   *
 399   * @ingroup themeable
 400   */
 401  function theme_overlay_disable_message($variables) {
 402    $element = $variables['element'];
 403  
 404    // Add CSS classes to hide the links from most sighted users, while keeping
 405    // them accessible to screen-reader users and keyboard-only users. To assist
 406    // screen-reader users, this message appears in both the parent and child
 407    // documents, but only the one in the child document is part of the tab order.
 408    foreach (array('profile_link', 'dismiss_message_link') as $key) {
 409      $element[$key]['#options']['attributes']['class'][] = 'element-invisible';
 410      if (overlay_get_mode() == 'child') {
 411        $element[$key]['#options']['attributes']['class'][] = 'element-focusable';
 412      }
 413    }
 414  
 415    // Render the links.
 416    $output = drupal_render($element['profile_link']) . ' ' . drupal_render($element['dismiss_message_link']);
 417  
 418    // Add a heading for screen-reader users. The heading doesn't need to be seen
 419    // by sighted users.
 420    $output = '<h3 class="element-invisible">' . t('Options for the administrative overlay') . '</h3>' . $output;
 421  
 422    // Wrap in a container for styling.
 423    $output = '<div id="overlay-disable-message" class="clearfix">' . $output . '</div>';
 424  
 425    return $output;
 426  }
 427  
 428  /**
 429   * Implements hook_block_list_alter().
 430   */
 431  function overlay_block_list_alter(&$blocks) {
 432    // If we are limiting rendering to a subset of page regions, hide all blocks
 433    // which appear in regions not on that list. Note that overlay_page_alter()
 434    // does a more comprehensive job of preventing unwanted regions from being
 435    // displayed (regardless of whether they contain blocks or not), but the
 436    // reason for duplicating effort here is performance; we do not even want
 437    // these blocks to be built if they are not going to be displayed.
 438    if ($regions_to_render = overlay_get_regions_to_render()) {
 439      foreach ($blocks as $bid => $block) {
 440        if (!in_array($block->region, $regions_to_render)) {
 441          unset($blocks[$bid]);
 442        }
 443      }
 444    }
 445  }
 446  
 447  /**
 448   * Implements hook_system_info_alter().
 449   *
 450   * Add default regions for the overlay.
 451   */
 452  function overlay_system_info_alter(&$info, $file, $type) {
 453    if ($type == 'theme') {
 454      $info['overlay_regions'][] = 'content';
 455      $info['overlay_regions'][] = 'help';
 456    }
 457  }
 458  
 459  /**
 460   * Implements hook_preprocess_html().
 461   *
 462   * If the current page request is inside the overlay, add appropriate classes
 463   * to the <body> element, and simplify the page title.
 464   *
 465   * @see overlay_get_mode()
 466   */
 467  function overlay_preprocess_html(&$variables) {
 468    if (overlay_get_mode() == 'child') {
 469      // Add overlay class, so themes can react to being displayed in the overlay.
 470      $variables['classes_array'][] = 'overlay';
 471    }
 472  }
 473  
 474  /**
 475   * Implements hook_preprocess_maintenance_page().
 476   *
 477   * If the current page request is inside the overlay, add appropriate classes
 478   * to the <body> element, and simplify the page title.
 479   *
 480   * @see overlay_preprocess_maintenance_page()
 481   */
 482  function overlay_preprocess_maintenance_page(&$variables) {
 483    overlay_preprocess_html($variables);
 484  }
 485  
 486  /**
 487   * Implements template_preprocess_HOOK() for overlay.tpl.php
 488   *
 489   * If the current page request is inside the overlay, add appropriate classes
 490   * to the <body> element, and simplify the page title.
 491   *
 492   * @see template_process_overlay()
 493   * @see overlay.tpl.php
 494   */
 495  function template_preprocess_overlay(&$variables) {
 496    $variables['tabs'] = menu_primary_local_tasks();
 497    $variables['title'] = drupal_get_title();
 498    $variables['disable_overlay'] = overlay_disable_message();
 499    $variables['content_attributes_array']['class'][] = 'clearfix';
 500  }
 501  
 502  /**
 503   * Implements template_process_HOOK() for overlay.tpl.php
 504   *
 505   * Places the rendered HTML for the page body into a top level variable.
 506   *
 507   * @see template_preprocess_overlay()
 508   * @see overlay.tpl.php
 509   */
 510  function template_process_overlay(&$variables) {
 511    $variables['page'] = $variables['page']['#children'];
 512  }
 513  
 514  /**
 515   * Implements hook_preprocess_page().
 516   *
 517   * If the current page request is inside the overlay, hide the tabs.
 518   *
 519   * @see overlay_get_mode()
 520   */
 521  function overlay_preprocess_page(&$variables) {
 522    if (overlay_get_mode() == 'child') {
 523      unset($variables['tabs']['#primary']);
 524    }
 525  }
 526  
 527  /**
 528   * Stores and returns whether an empty page override is needed.
 529   *
 530   * This is used to prevent a page request which closes the overlay (for
 531   * example, a form submission) from being fully re-rendered before the overlay
 532   * is closed. Instead, we store a variable which will cause the page to be
 533   * rendered by a delivery callback function that does not actually print
 534   * visible HTML (but rather only the bare minimum scripts and styles necessary
 535   * to trigger the overlay to close), thereby allowing the dialog to be closed
 536   * faster and with less interruption, and also allowing the display of messages
 537   * to be deferred to the parent window (rather than displaying them in the
 538   * child window, which will close before the user has had a chance to read
 539   * them).
 540   *
 541   * @param $value
 542   *   By default, an empty page will not be displayed. Set to TRUE to request
 543   *   an empty page display, or FALSE to disable the empty page display (if it
 544   *   was previously enabled on this page request).
 545   *
 546   * @return
 547   *   TRUE if the current behavior is to display an empty page, or FALSE if not.
 548   *
 549   * @see overlay_page_delivery_callback_alter()
 550   */
 551  function overlay_display_empty_page($value = NULL) {
 552    $display_empty_page = &drupal_static(__FUNCTION__, FALSE);
 553    if (isset($value)) {
 554      $display_empty_page = $value;
 555    }
 556    return $display_empty_page;
 557  }
 558  
 559  /**
 560   * Implements hook_page_delivery_callback_alter().
 561   */
 562  function overlay_page_delivery_callback_alter(&$callback) {
 563    if (overlay_display_empty_page()) {
 564      $callback = 'overlay_deliver_empty_page';
 565    }
 566  }
 567  
 568  /**
 569   * Prints an empty page.
 570   *
 571   * This function is used to print out a bare minimum empty page which still has
 572   * the scripts and styles necessary in order to trigger the overlay to close.
 573   */
 574  function overlay_deliver_empty_page() {
 575    $empty_page = '<html><head><title></title>' . drupal_get_css() . drupal_get_js() . '</head><body class="overlay"></body></html>';
 576    print $empty_page;
 577    drupal_exit();
 578  }
 579  
 580  /**
 581   * Gets the current overlay mode.
 582   *
 583   * @see overlay_set_mode()
 584   */
 585  function overlay_get_mode() {
 586    return overlay_set_mode(NULL);
 587  }
 588  
 589  /**
 590   * Sets the overlay mode and adds proper JavaScript and styles to the page.
 591   *
 592   * Note that since setting the overlay mode triggers a variety of behaviors
 593   * (including hooks being invoked), it can only be done once per page request.
 594   * Therefore, the first call to this function which passes along a value of the
 595   * $mode parameter controls the overlay mode that will be used.
 596   *
 597   * @param $mode
 598   *   To set the mode, pass in one of the following values:
 599   *   - 'parent': This is used in the context of a parent window (a regular
 600   *     browser window). If set, JavaScript is added so that administrative
 601   *     links in the parent window will open in an overlay.
 602   *   - 'child': This is used in the context of the child overlay window (the
 603   *     page actually appearing within the overlay iframe). If set, JavaScript
 604   *     and CSS are added so that Drupal behaves nicely from within the overlay.
 605   *   - 'none': This is used to avoid adding any overlay-related code to the
 606   *     page at all. Modules can set this to explicitly prevent the overlay from
 607   *     being used. For example, since the overlay module itself sets the mode
 608   *     to 'parent' or 'child' in overlay_init() when certain conditions are
 609   *     met, other modules which want to override that behavior can do so by
 610   *     setting the mode to 'none' earlier in the page request - e.g., in their
 611   *     own hook_init() implementations, if they have a lower weight.
 612   *   This parameter is optional, and if omitted, the current mode will be
 613   *   returned with no action taken.
 614   *
 615   * @return
 616   *   The current mode, if any has been set, or NULL if no mode has been set.
 617   *
 618   * @ingroup overlay_api
 619   * @see overlay_init()
 620   */
 621  function overlay_set_mode($mode = NULL) {
 622    global $base_path;
 623    $overlay_mode = &drupal_static(__FUNCTION__);
 624  
 625    // Make sure external resources are not included more than once. Also return
 626    // the current mode, if no mode was specified.
 627    if (isset($overlay_mode) || !isset($mode)) {
 628      return $overlay_mode;
 629    }
 630    $overlay_mode = $mode;
 631  
 632    switch ($overlay_mode) {
 633      case 'parent':
 634        drupal_add_library('overlay', 'parent');
 635  
 636        // Allow modules to act upon overlay events.
 637        module_invoke_all('overlay_parent_initialize');
 638        break;
 639  
 640      case 'child':
 641        drupal_add_library('overlay', 'child');
 642  
 643        // Allow modules to act upon overlay events.
 644        module_invoke_all('overlay_child_initialize');
 645        break;
 646    }
 647    return $overlay_mode;
 648  }
 649  
 650  /**
 651   * Implements hook_overlay_parent_initialize().
 652   */
 653  function overlay_overlay_parent_initialize() {
 654    // Let the client side know which paths are administrative.
 655    $paths = path_get_admin_paths();
 656    foreach ($paths as &$type) {
 657      $type = str_replace('<front>', variable_get('site_frontpage', 'node'), $type);
 658    }
 659    drupal_add_js(array('overlay' => array('paths' => $paths)), 'setting');
 660    $path_prefixes = array();
 661    if (module_exists('locale') && variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX) == LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX) {
 662      // Get languages grouped by status and select only the enabled ones.
 663      $languages = language_list('enabled');
 664      $languages = $languages[1];
 665  
 666      $path_prefixes = array();
 667      foreach ($languages as $language) {
 668        if ($language->prefix) {
 669          $path_prefixes[] = $language->prefix;
 670        }
 671      }
 672    }
 673    drupal_add_js(array('overlay' => array('pathPrefixes' => $path_prefixes)), 'setting');
 674    // Pass along the Ajax callback for rerendering sections of the parent window.
 675    drupal_add_js(array('overlay' => array('ajaxCallback' => 'overlay-ajax')), 'setting');
 676  }
 677  
 678  /**
 679   * Implements hook_overlay_child_initialize().
 680   */
 681  function overlay_overlay_child_initialize() {
 682    // Check if the parent window needs to refresh any page regions on this page
 683    // request.
 684    overlay_trigger_refresh();
 685    // If this is a POST request, or a GET request with a token parameter, we
 686    // have an indication that something in the supplemental regions of the
 687    // overlay might change during the current page request. We therefore store
 688    // the initial rendered content of those regions here, so that we can compare
 689    // it to the same content rendered in overlay_exit(), at the end of the page
 690    // request. This allows us to check if anything actually did change, and, if
 691    // so, trigger an immediate Ajax refresh of the parent window.
 692    if (!empty($_POST) || isset($_GET['token'])) {
 693      foreach (overlay_supplemental_regions() as $region) {
 694        overlay_store_rendered_content($region, overlay_render_region($region));
 695      }
 696      // In addition, notify the parent window that when the overlay closes,
 697      // the entire parent window should be refreshed.
 698      overlay_request_page_refresh();
 699    }
 700    // Indicate that when the main page rendering occurs later in the page
 701    // request, only the regions that appear within the overlay should be
 702    // rendered.
 703    overlay_set_regions_to_render(overlay_regions());
 704  }
 705  
 706  /**
 707   * Requests that the overlay overlay closes when the page is displayed.
 708   *
 709   * @param $redirect
 710   *   (optional) The path that should open in the parent window after the
 711   *   overlay closes. If not set, no redirect will be performed on the parent
 712   *   window.
 713   *
 714   * @param $redirect_options
 715   *   (optional) An associative array of options to use when generating the
 716   *   redirect URL.
 717   */
 718  function overlay_close_dialog($redirect = NULL, $redirect_options = array()) {
 719    $settings = array(
 720      'overlayChild' => array(
 721        'closeOverlay' => TRUE,
 722      ),
 723    );
 724  
 725    // Tell the child window to perform the redirection when requested to.
 726    if (isset($redirect)) {
 727      $settings['overlayChild']['redirect'] = url($redirect, $redirect_options);
 728    }
 729  
 730    drupal_add_js($settings, array('type' => 'setting'));
 731  
 732    // Since we are closing the overlay as soon as the page is displayed, we do
 733    // not want to show any of the page's actual content.
 734    overlay_display_empty_page(TRUE);
 735  }
 736  
 737  /**
 738   * Returns a list of page regions that appear in the overlay.
 739   *
 740   * Overlay regions correspond to the entire contents of the overlay child
 741   * window and are refreshed each time a new page request is made within the
 742   * overlay.
 743   *
 744   * @return
 745   *   An array of region names that correspond to those which appear in the
 746   *   overlay, within the theme that is being used to display the current page.
 747   *
 748   * @see overlay_supplemental_regions()
 749   */
 750  function overlay_regions() {
 751    return _overlay_region_list('overlay_regions');
 752  }
 753  
 754  /**
 755   * Returns a list of supplemental page regions for the overlay.
 756   *
 757   * Supplemental overlay regions are those which are technically part of the
 758   * parent window, but appear to the user as being related to the overlay
 759   * (usually because they are displayed next to, rather than underneath, the
 760   * main overlay regions) and therefore need to be dynamically refreshed if any
 761   * administrative actions taken within the overlay change their contents.
 762   *
 763   * An example of a typical overlay supplemental region would be the 'page_top'
 764   * region, in the case where a toolbar is being displayed there.
 765   *
 766   * @return
 767   *   An array of region names that correspond to supplemental overlay regions,
 768   *   within the theme that is being used to display the current page.
 769   *
 770   * @see overlay_regions()
 771   */
 772  function overlay_supplemental_regions() {
 773    return _overlay_region_list('overlay_supplemental_regions');
 774  }
 775  
 776  /**
 777   * Returns a list of page regions related to the overlay.
 778   *
 779   * @param $type
 780   *   The type of regions to return. This can either be 'overlay_regions' or
 781   *   'overlay_supplemental_regions'.
 782   *
 783   * @return
 784   *   An array of region names of the given type, within the theme that is being
 785   *   used to display the current page.
 786   *
 787   * @see overlay_regions()
 788   * @see overlay_supplemental_regions()
 789   */
 790  function _overlay_region_list($type) {
 791    // Obtain the current theme. We need to first make sure the theme system is
 792    // initialized, since this function can be called early in the page request.
 793    drupal_theme_initialize();
 794    $themes = list_themes();
 795    $theme = $themes[$GLOBALS['theme']];
 796    // Return the list of regions stored within the theme's info array, or an
 797    // empty array if no regions of the appropriate type are defined.
 798    return !empty($theme->info[$type]) ? $theme->info[$type] : array();
 799  }
 800  
 801  /**
 802   * Returns a list of page regions that rendering should be limited to.
 803   *
 804   * @return
 805   *   An array containing the names of the regions that will be rendered when
 806   *   drupal_render_page() is called. If empty, then no limits will be imposed,
 807   *   and all regions of the page will be rendered.
 808   *
 809   * @see overlay_page_alter()
 810   * @see overlay_block_list_alter()
 811   * @see overlay_set_regions_to_render()
 812   */
 813  function overlay_get_regions_to_render() {
 814    return overlay_set_regions_to_render();
 815  }
 816  
 817  /**
 818   * Sets the regions of the page that rendering will be limited to.
 819   *
 820   * @param $regions
 821   *   (Optional) An array containing the names of the regions that should be
 822   *   rendered when drupal_render_page() is called. Pass in an empty array to
 823   *   remove all limits and cause drupal_render_page() to render all page
 824   *   regions (the default behavior). If this parameter is omitted, no change
 825   *   will be made to the current list of regions to render.
 826   *
 827   * @return
 828   *   The current list of regions to render, or an empty array if the regions
 829   *   are not being limited.
 830   *
 831   * @see overlay_page_alter()
 832   * @see overlay_block_list_alter()
 833   * @see overlay_get_regions_to_render()
 834   */
 835  function overlay_set_regions_to_render($regions = NULL) {
 836    $regions_to_render = &drupal_static(__FUNCTION__, array());
 837    if (isset($regions)) {
 838      $regions_to_render = $regions;
 839    }
 840    return $regions_to_render;
 841  }
 842  
 843  /**
 844   * Renders an individual page region.
 845   *
 846   * This function is primarily intended to be used for checking the content of
 847   * supplemental overlay regions (e.g., a region containing a toolbar). Passing
 848   * in a region that is intended to display the main page content is not
 849   * supported; the region will be rendered by this function, but the main page
 850   * content will not appear in it. In addition, although this function returns
 851   * the rendered HTML for the provided region, it does not place it on the final
 852   * page, nor add any of its associated JavaScript or CSS to the page.
 853   *
 854   * @param $region
 855   *   The name of the page region that should be rendered.
 856   *
 857   * @return
 858   *   The rendered HTML of the provided region.
 859   */
 860  function overlay_render_region($region) {
 861    // Indicate the region that we will be rendering, so that other regions will
 862    // be hidden by overlay_page_alter() and overlay_block_list_alter().
 863    overlay_set_regions_to_render(array($region));
 864    // Do what is necessary to force drupal_render_page() to only display HTML
 865    // from the requested region. Specifically, declare that the main page
 866    // content does not need to automatically be added to the page, and pass in
 867    // a page array that has all theme functions removed (so that overall HTML
 868    // for the page will not be added either).
 869    $system_main_content_added = &drupal_static('system_main_content_added');
 870    $system_main_content_added = TRUE;
 871    $page = array(
 872      '#type' => 'page',
 873      '#theme' => NULL,
 874      '#theme_wrappers' => array(),
 875    );
 876    // Render the region, but do not cache any JavaScript or CSS associated with
 877    // it. This region might not be included the next time drupal_render_page()
 878    // is called, and we do not want its JavaScript or CSS to erroneously appear
 879    // on the final rendered page.
 880    $original_js = drupal_add_js();
 881    $original_css = drupal_add_css();
 882    $original_libraries = drupal_static('drupal_add_library');
 883    $js = &drupal_static('drupal_add_js');
 884    $css = &drupal_static('drupal_add_css');
 885    $libraries = &drupal_static('drupal_add_library');
 886    $markup = drupal_render_page($page);
 887    $js = $original_js;
 888    $css = $original_css;
 889    $libraries = $original_libraries;
 890    // Indicate that the main page content has not, in fact, been displayed, so
 891    // that future calls to drupal_render_page() will be able to render it
 892    // correctly.
 893    $system_main_content_added = FALSE;
 894    // Restore the original behavior of rendering all regions for the next time
 895    // drupal_render_page() is called.
 896    overlay_set_regions_to_render(array());
 897    return $markup;
 898  }
 899  
 900  /**
 901   * Returns any rendered content that was stored earlier in the page request.
 902   *
 903   * @return
 904   *   An array of all rendered HTML that was stored earlier in the page request,
 905   *   keyed by the identifier with which it was stored. If no content was
 906   *   stored, an empty array is returned.
 907   *
 908   * @see overlay_store_rendered_content()
 909   */
 910  function overlay_get_rendered_content() {
 911    return overlay_store_rendered_content();
 912  }
 913  
 914  /**
 915   * Stores strings representing rendered HTML content.
 916   *
 917   * This function is used to keep a static cache of rendered content that can be
 918   * referred to later in the page request.
 919   *
 920   * @param $id
 921   *   (Optional) An identifier for the content which is being stored, which will
 922   *   be used as an array key in the returned array. If omitted, no change will
 923   *   be made to the current stored data.
 924   * @param $content
 925   *   (Optional) A string representing the rendered data to store. This only has
 926   *   an effect if $id is also provided.
 927   *
 928   * @return
 929   *   An array representing all data that is currently being stored, or an empty
 930   *   array if there is none.
 931   *
 932   * @see overlay_get_rendered_content()
 933   */
 934  function overlay_store_rendered_content($id = NULL, $content = NULL) {
 935    $rendered_content = &drupal_static(__FUNCTION__, array());
 936    if (isset($id)) {
 937      $rendered_content[$id] = $content;
 938    }
 939    return $rendered_content;
 940  }
 941  
 942  /**
 943   * Requests that the parent window refreshes a particular page region.
 944   *
 945   * @param $region
 946   *   The name of the page region to refresh. The parent window will trigger a
 947   *   refresh of this region on the next page load.
 948   *
 949   * @see overlay_trigger_refresh()
 950   * @see Drupal.overlay.refreshRegions()
 951   */
 952  function overlay_request_refresh($region) {
 953    $class = drupal_region_class($region);
 954    $_SESSION['overlay_regions_to_refresh'][] = array($class => $region);
 955  }
 956  
 957  /**
 958   * Requests that the entire parent window is reloaded when the overlay closes.
 959   *
 960   * @see overlay_trigger_refresh()
 961   */
 962  function overlay_request_page_refresh() {
 963    $_SESSION['overlay_refresh_parent'] = TRUE;
 964  }
 965  
 966  /**
 967   * Checks if the parent window needs to be refreshed on this page load.
 968   *
 969   * If the previous page load requested that any page regions be refreshed, or
 970   * if it requested that the entire page be refreshed when the overlay closes,
 971   * pass that request via JavaScript to the child window, so it can in turn pass
 972   * the request to the parent window.
 973   *
 974   * @see overlay_request_refresh()
 975   * @see overlay_request_page_refresh()
 976   * @see Drupal.overlay.refreshRegions()
 977   */
 978  function overlay_trigger_refresh() {
 979    if (!empty($_SESSION['overlay_regions_to_refresh'])) {
 980      $settings = array(
 981        'overlayChild' => array(
 982          'refreshRegions' => $_SESSION['overlay_regions_to_refresh'],
 983        ),
 984      );
 985      drupal_add_js($settings, array('type' => 'setting'));
 986      unset($_SESSION['overlay_regions_to_refresh']);
 987    }
 988    if (!empty($_SESSION['overlay_refresh_parent'])) {
 989      drupal_add_js(array('overlayChild' => array('refreshPage' => TRUE)), array('type' => 'setting'));
 990      unset($_SESSION['overlay_refresh_parent']);
 991    }
 992  }
 993  
 994  /**
 995   * Prints the markup obtained by rendering a single region of the page.
 996   *
 997   * This function is intended to be called via Ajax.
 998   *
 999   * @param $region
1000   *   The name of the page region to render.
1001   *
1002   * @see Drupal.overlay.refreshRegions()
1003   */
1004  function overlay_ajax_render_region($region) {
1005    print overlay_render_region($region);
1006  }

title

Description

title

Description

title

Description

title

title

Body