You are here

popups.module in Popups API (Ajax Dialogs) 5

Same filename and directory in other branches
  1. 6.2 popups.module
  2. 6 popups.module
  3. 7 popups.module

popups.module

This module uses popup modal dalogs to enhance the Administration Pages by allowing pages to be shown inside modual dialogs. It also provides a hook_popups for other pages that want to use this functionality.

@todo

  • Adding Javascript into popups doesn't always work.
  • tabledrag onmouse up action.
  • user.js and teaser.js bugs.
  • Cache the results of hook_popups.
  • Taxonomy > Add vocab. Adding second item to page does not trigger d-n-d transformation. Might be a problem with Taxonomy. Menus doesn't have problem (adds d-n-d on first item).

File

popups.module
View source
<?php

/**
 * @file popups.module
 *
 * This module uses popup modal dalogs to enhance the Administration Pages by allowing pages
 *  to be shown inside modual dialogs.
 * It also provides a hook_popups for other pages that want to use this functionality. 
 *
 * @todo 
 * * Adding Javascript into popups doesn't always work.
 * *   tabledrag onmouse up action. 
 * *   user.js and teaser.js bugs.
 * * Cache the results of hook_popups.
 * * Taxonomy > Add vocab.  Adding second item to page does not trigger d-n-d transformation.
 *     Might be a problem with Taxonomy.  Menus doesn't have problem (adds d-n-d on first item).
 */

// **************************************************************************
// CORE HOOK FUNCTIONS   ****************************************************
// **************************************************************************

/**
 * hook_menu
 *
 * @return array of new menu items.
 */
function popups_menu() {

  // Themable page save dialog.
  $items[] = array(
    'path' => 'popups/save_dialog',
    'callback' => 'theme',
    'callback arguments' => array(
      'popup_save_dialog',
    ),
    'access' => TRUE,
    'type' => MENU_CALLBACK,
  );

  // Admin Settings.
  $items[] = array(
    'path' => 'admin/settings/popups',
    'callback' => 'drupal_get_form',
    'callback arguments' => array(
      'popups_admin_settings',
    ),
    'title' => t('Popups'),
    'access' => user_access('administer site configuration'),
    'description' => 'Configure the page-in-a-dialog behavior.',
  );

  // Items for testing.
  $items[] = array(
    'path' => 'popups/test',
    'title' => t('Popup Test'),
    'callback' => '_popups_test_popups',
    'type' => MENU_CALLBACK,
    'access' => TRUE,
  );
  $items[] = array(
    'path' => 'popups/test/response',
    'title' => t('Popup Test'),
    'callback' => '_popups_test_response',
    'type' => MENU_CALLBACK,
    'access' => TRUE,
  );
  $items[] = array(
    'path' => 'popups/test/namechange',
    'callback' => 'drupal_get_form',
    'callback arguments' => array(
      '_popups_test_namechange',
    ),
    'type' => MENU_CALLBACK,
    'access callback' => TRUE,
  );
  return $items;
}

/**
 * hook_init
 * 
 * Look at the page path and see if popup behavior has been requested for any links in this page.
 */
function popups_init() {
  $popups = popups_get_popups();
  if (isset($popups[$_GET['q']])) {
    popups_add_popups($popups[$_GET['q']]);
  }
  if (isset($_SERVER['HTTP_X_DRUPAL_RENDER_MODE'])) {
    $render_mode = $_SERVER['HTTP_X_DRUPAL_RENDER_MODE'];
  }

  // Check and see if the page_override param is in the URL.
  // Note - the magic happens here.
  // Need to cache the page_override flag in the session, so it will effect
  // the results page that follows a form submission.
  if ($render_mode == 'json/popups') {
    $_SESSION['page_override'] = TRUE;
  }

  // Move the page_override flag back out of the session.
  if (isset($_SESSION['page_override'])) {

    // This call will not return on form submission.
    $content = menu_execute_active_handler();

    // The call did return, so it wasn't a form request,
    // so we are returning a result, so clear the session flag.
    $override = $_SESSION['page_override'];
    unset($_SESSION['page_override']);

    // Menu status constants are integers; page content is a string.
    if (isset($content) && !is_int($content) && isset($override)) {
      print popups_render_as_json($content);
      exit;

      // Do not continue processing request in index.html.
    }
  }
}

/**
 * hook_theme - doesn't exist in D5
 *
 *
function popups_theme($existing, $type) {  
  return array(
    'popups_popup' => array(
      'template' => 'popups-popup',
//      'arguments' => array('content' => NULL),
    ),
    'popups_save_dialog' => array(),      
  );
}
*/
function theme_popups_dialog() {
  return '<div id="popups">
  <div id="popups-title">
    <div id="popups-close"><a href="#">' . t('Close') . '</a></div>
    <div class="title">%title</div>
    <div class="clear-block"></div>
  </div>
  <div id="popups-body">%body</div>
  <div id="popups-buttons">%buttons</div>
  <div id="popups-footer"></div>
</div>';
}
function popups_render_as_json($content) {
  $path = $_GET['q'];

  // Get current path from params.
  drupal_set_header('Content-Type: text/javascript; charset=utf-8');
  return drupal_to_js(array(
    'title' => drupal_get_title(),
    'messages' => theme('status_messages'),
    'path' => $path,
    'content' => $content,
  ));
}

/**
 * hook_form_alter
 * 
 * Look at the form_id and see if popup behavior has been requested for any links in this form.
 *
 * @param form_array $form
 * @param array $form_state
 * @param str $form_id: 
 */

//function popups_form_alter(&$form, $form_state, $form_id) { $form_id, &$form
function popups_form_alter($form_id, &$form) {

  // Add popup behavior to the form if requested.
  $popups = popups_get_popups();
  if (isset($popups[$form_id])) {
    popups_add_popups($popups[$form_id]);
  }

  // Alter the theme configuration pages, to add a per-theme-content selector.
  $theme = arg(4);
  if ($form_id == 'system_theme_settings' && $theme) {
    $form['popups'] = array(
      '#type' => 'fieldset',
      '#title' => t('Popup Settings'),
      '#weight' => -2,
    );
    $form['popups']['popups_content_selector'] = array(
      '#type' => 'textfield',
      '#title' => t('Content Selector'),
      '#default_value' => variable_get('popups_' . $theme . '_content_selector', 'div#content'),
      '#description' => t("jQuery selector to define the page's content area on this theme."),
    );
    $form['popups']['popups_theme'] = array(
      '#type' => 'hidden',
      '#value' => $theme,
    );

    //    $form['#submit'][] = 'popups_theme_settings_form_submit'; // D6 format.
    $form['#submit']['popups_theme_settings_form_submit'] = array();

    // D5 format.
  }
}
function popups_theme_settings_form_submit($form_id, $form_values) {
  $theme = $form_values['popups_theme'];
  $content_selector = $form_values['popups_content_selector'];
  variable_set('popups_' . $theme . '_content_selector', $content_selector);

  //  drupal_set_message("setting selector to $content_selector for theme $theme");
}

// **************************************************************************
// UTILITY FUNCTIONS   ******************************************************
// **************************************************************************

/**
 * Build the list of popup rules from all modules that implement hook_popups.
 * 
 * @todo - Add some caching so we don't rebuild everytime.
 */
function popups_get_popups() {
  static $popups = NULL;
  if (!isset($popups)) {
    $popups = module_invoke_all('popups');
  }
  return $popups;
}

/**
 * Attach the popup behavior to the page.
 * 
 * The default behavoir of a popup is to open a form that will modify the original page.  The popup submits
 * the form and reloads the original page with the resulting new content. The popup then replaces
 * the original page's content area with the new copy of that content area.
 *
 * @param array $rule: Array of rules to apply to the page or form, keyed by jQuery link selector.
 * Options:
 *   noReload: Does the popup NOT modify the original page (Default: false).
 *   titleSelectors: Array of jQuery selectors to place the new page title (Default: do nothing).
 *   targetSelectors: Array (or hash) of jQuery selectors with areas to update (Default: use single theme-wide setting)
 *   forceReturn: url to force a stop to work flow (only use in conjunction with noReload).
 *   href: override the href in the a element, or attach an href to a non-link element.
 *   width: override the width specified in the css.
 *   additionalJavascript: Array of JavaScript files that must be included to correctly run the page in the popup. 
 *   additionalCss: Array of CSS files that must be included to correctly style the page in the popup. 
 *  
 * Rule Format Example:
 * 'admin/content/taxonomy' => array( // Act only on the links on this page. 
 *   'div#tabs-wrapper a:eq(1)',  // No options, so use defaults. Note: Selector must select <a> element(s).
 *   'table td:nth-child(2) a' => array( 
 *     'noReload' => true, // Popup will not modify original page.
 *   ),
 * )
 * 
 */
function popups_add_popups($rules = null) {
  static $added = FALSE;
  $settings = array(
    'popups' => array(),
  );
  if (is_array($rules)) {
    $settings['popups']['links'] = array();
    foreach ($rules as $popup_selector => $options) {
      if (is_array($options)) {
        $settings['popups']['links'][$popup_selector] = $options;
        if (isset($options['additionalJavascript']) && is_array($options['additionalJavascript'])) {
          foreach ($options['additionalJavascript'] as $file) {
            drupal_add_js($file);
          }
        }
        if (isset($options['additionalCss']) && is_array($options['additionalCss'])) {
          foreach ($options['additionalCss'] as $file) {
            drupal_add_css($file);
          }
        }
      }
      else {
        $settings['popups']['links'][$options] = array();
      }
    }
    if ($added) {
      drupal_add_js($settings, 'setting');
    }
  }
  if (!$added) {
    drupal_add_css(drupal_get_path('module', 'popups') . '/popups.css');
    drupal_add_css(drupal_get_path('module', 'popups') . '/popups-skin.css');
    drupal_add_js(drupal_get_path('module', 'popups') . '/popups.js');
    drupal_add_js(drupal_get_path('module', 'popups') . '/dimensions/dimensions.js');
    drupal_add_js(drupal_get_path('module', 'popups') . '/form/form.js');
    drupal_add_js('misc/jquery.form.js');

    // Determing if we are showing the default theme or a custom theme.
    global $custom_theme;
    $theme = $custom_theme;
    if (!$theme) {
      $theme = variable_get('theme_default', 'none');
    }
    $defaultTargetSelector = variable_get('popups_' . $theme . '_content_selector', 'div#content');
    $settings['popups']['defaultTargetSelector'] = $defaultTargetSelector;
    $settings['popups']['modulePath'] = base_path() . drupal_get_path('module', 'popups');
    $settings['popups']['popupFinalMessage'] = variable_get('popups_popup_final_message', 1);
    drupal_add_js($settings, 'setting');
    $added = TRUE;
  }
}

/**
 * hook_popups
 * 
 * This implements hook_popups, defined in popups_get_popups.
 * Adding popup behavior to the core admin pages has been moved to popups_admin.
 * See the comments in popups_add_popups for explination of the options.
 *
 * @return: Array of link selectors to apply popup behavior to.
 *          Keyed by path or form_id.
 */
function popups_popups() {
  return array(
    'popups/test' => array(
      // test.
      '#test-popup' => array(
        'additionalJavascript' => array(
          'misc/collapse.js',
        ),
        'behaviors' => array(
          'Drupal.popups.collapsibleBehavior',
        ),
        'forceReturn' => 'node/add/page',
      ),
    ),
  );
}

// **************************************************************************
// ADMIN SETTINGS   *********************************************************
// **************************************************************************
function popups_admin_settings() {
  drupal_set_title("Popups Settings");
  $form = array();
  $form['popups_popup_final_message'] = array(
    '#type' => 'checkbox',
    '#title' => t('Do NOT auto-close final message.'),
    '#default_value' => variable_get('popups_popup_final_message', 1),
  );
  return system_settings_form($form);
}

// **************************************************************************
// TESTING   ****************************************************************
// **************************************************************************
function _popups_test_popups() {
  popups_add_popups();
  $output = '<ul id="test-list">';
  $output .= '<li>' . l("Pop up entire local page.", 'popups/test/response', array(
    'class' => 'popups',
  ));
  $output .= "<li>" . l("Pop with options (href override).", 'popups/test/', array(
    'class' => 'popups',
    'on-popups-options' => '{href: "test/response"}',
  ));
  $output .= "<li>" . l("Pop with options (width=200px).", 'popups/test/response', array(
    'class' => 'popups',
    'on-popups-options' => '{width: "200px"}',
  ));
  $output .= "<li class=\"popups\" on-popups-options=\"{href: 'test/response'}\">Non-link popup</li>";
  $output .= '<li>' . l("Add Page (hook).", 'node/add/page', array(
    'id' => 'test-popup',
  ));
  $output .= '<li>' . l("Add Page (attribute).", 'node/add/page', array(
    'class' => 'popups-form',
    'on-popups-options' => '{behaviors: ["Drupal.popups.collapsibleBehavior"]}',
  ), 'destination=popups/test');
  $output .= '<li>' . l("Change Settings and reload page.", 'admin/settings/popups', array(
    'class' => 'popups-form',
  ), 'destination=popups/test');
  $output .= "<span id='response1'> (Auto Fade checkbox is: " . (variable_get('popups_popup_final_message', 1) ? 'on' : 'off') . ')</span>';
  $output .= '<li>' . l("Change Settings and reload target.", 'admin/settings/popups', array(
    'id' => 'reload-target',
  ), 'destination=popups/test');
  $output .= "<span id='response2'> (Auto Fade checkbox is: " . (variable_get('popups_popup_final_message', 1) ? 'on' : 'off') . ')</span>';
  popups_add_popups(array(
    '#reload-target' => array(
      'targetSelectors' => array(
        '#response2',
      ),
    ),
  ));
  $output .= '<li>' . l("Change Settings and cherry pick.", 'admin/settings/popups', array(
    'id' => 'foo',
    'class' => 'popups-form',
    'on-popups-options' => '{targetSelectors: {"label": "#foo", "label:first": "#test-list li:first"}, forceReturn: "admin/settings/popups"}',
  ));
  $output .= '<li>' . l("Pop up defined by popups_add_popups rule.", 'popups/test/response', array(
    'id' => 'rule-test',
  ));
  popups_add_popups(array(
    '#rule-test' => array(
      'width' => '300px',
    ),
  ));
  $output .= '<li>' . l("Change Page Title.", 'popups/test/namechange', array(
    'id' => 'title-test',
  ));
  popups_add_popups(array(
    '#title-test' => array(
      'titleSelectors' => array(
        '#page-title',
      ),
      'forceReturn' => 'popups/test/namechange',
    ),
  ));
  $output .= "</ul>";
  return $output;
}
function _popups_test_response() {
  drupal_set_title("A Popup Test");
  return '<div>Hello World</div><a href="#" class="popups">Popup chaining test</a>';
}
function _popups_test_namechange() {
  drupal_set_title("New Name for Test Page");
  $form = array();
  $form['popups_popup_final_message'] = array(
    '#type' => 'submit',
    '#value' => t('Test Name Change'),
  );
  return $form;
}

Functions

Namesort descending Description
popups_add_popups Attach the popup behavior to the page.
popups_admin_settings
popups_form_alter
popups_get_popups Build the list of popup rules from all modules that implement hook_popups.
popups_init hook_init
popups_menu hook_menu
popups_popups hook_popups
popups_render_as_json
popups_theme_settings_form_submit
theme_popups_dialog hook_theme - doesn't exist in D5
_popups_test_namechange
_popups_test_popups
_popups_test_response