You are here

hide_submit.module in Hide submit button 5

Same filename and directory in other branches
  1. 6 hide_submit.module
  2. 7.2 hide_submit.module
  3. 7 hide_submit.module

File

hide_submit.module
View source
<?php

/**
 * @file
 * Hide the submit button after clicked to prevent/reduce duplicate postings.
 *
 * Using a small jQuery snippet, this module will hide submit buttons
 * afted clicked to prevent/reduce duplicate postings.
 * A message and a nice loader animation will be displayed
 * So the user will know its request is being processed
 */
include_once "hide_submit_admin.inc";

// --- Constants ---
// Script load options
define('HIDE_SUBMIT_IN_CONTENT_ADD_EDIT', 0);
define('HIDE_SUBMIT_IN_ALL_PAGES', 1);
define('HIDE_SUBMIT_IN_LISTED_PAGES', 2);
define('HIDE_SUBMIT_EXCLUDE_LISTED_PAGES', 3);

// Default load option
define('HIDE_SUBMIT_DEFAULT_JS_LOAD', 0);

// Script mode options
define('HIDE_SUBMIT_MODE_HIDE', 0);
define('HIDE_SUBMIT_MODE_DISABLE', 1);
define('HIDE_SUBMIT_IMG_DIRECTORY', '/hide_submit');

// <file_directory_path>/hide_submit
define('HIDE_SUBMIT_DEFAULT_IMAGE_BASENAME', 'loader.gif');
define('HIDE_SUBMIT_EXCLUDE_CLASS', 'hide-submit-exclude');
define('HIDE_SUBMIT_EXCLUDE_LISTED_FORMS', 0);
define('HIDE_SUBMIT_EXCLUDE_UNLISTED_FORMS', 1);

/**
 * Implementation of hook_help().
 */
function hide_submit_help($section) {
  $output = '';
  switch ($section) {
    case 'admin/help#hide_submit':
    case 'admin/settings/hide-submit':
      $output = '<p>' . t('The hide_submit module provides a way to hide the submit button in a form after it has been clicked. This will indicate to the user that his or her request is being processed and helps to prevent duplicate postings from impatient "double clickers".') . '</p>' . '<p>' . t('For more information please visit the !project page or the !documentation page', array(
        '!documentation' => l('documentation', 'http://drupal.org/node/338935'),
        '!project' => l('hide submit project', 'http://drupal.org/project/hide_submit'),
      )) . '</p>';
      if (module_exists('advanced_help')) {
        $output .= '<p>' . theme('advanced_help_topic', 'hide_submit', 'using-hide-submit') . '&nbsp;' . t('Click the icon to read the extended help.');
      }
      break;
  }
  return $output;
}

/**
 * Implementation of hook_menu
 */
function hide_submit_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/settings/hide-submit',
      'title' => 'Hide Submit',
      'description' => 'Configure hide submit',
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'hide_submit_admin_settings',
      ),
      'access' => user_access('administer site configuration'),
      'file' => 'hide_submit_admin.inc',
    );
    $items[] = array(
      'path' => 'admin/settings/hide-submit/settings',
      'title' => 'Hide Submit',
      'file' => 'hide_submit_admin.inc',
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => 10,
    );
  }
  else {
    $delete_path = 'admin/settings/hide-submit/delete';
    $path_action = substr($_GET['q'], 0, strlen($delete_path));
    if ($path_action === $delete_path) {
      $items[] = array(
        'path' => 'admin/settings/hide-submit/delete/' . arg(4),
        'title' => 'Confirm delete',
        'description' => 'Delete an image file',
        'callback' => 'drupal_get_form',
        'callback arguments' => array(
          'hide_submit_admin_delete_image',
          arg(4),
        ),
        'access' => user_access('administer site configuration'),
        'type' => MENU_CALLBACK,
      );
    }
  }
  return $items;
}

/**
 * Implementation of hook_form_alter
 *
 * Used to add "hide-submit-exclude" class to some forms
 * Avoid conflicts and refine hiding
*/
function hide_submit_form_alter($form_id, &$form) {
  $exclude_forms = explode("\r\n", variable_get('hide_submit_form_exclusion', 'shoutbox_add_form'));
  $found = FALSE;
  $mode = variable_get('hide_submit_form_exclusion_mode', HIDE_SUBMIT_EXCLUDE_LISTED_FORMS);
  foreach ($exclude_forms as $exclude_form_id) {
    if ($form_id == $exclude_form_id) {
      $found = TRUE;
      if ($mode == HIDE_SUBMIT_EXCLUDE_LISTED_FORMS) {
        _hide_submit_add_exclude_class($form);
        if (_hide_submit_debug_on()) {
          drupal_set_message(t("hide_submit: Excluding form %form", array(
            '%form' => $exclude_form_id,
          )));
        }
      }
    }
  }
  if (!$found && $mode == HIDE_SUBMIT_EXCLUDE_UNLISTED_FORMS) {
    _hide_submit_add_exclude_class($form);
    if (_hide_submit_debug_on()) {
      drupal_set_message(t("hide_submit: Excluding form %form", array(
        '%form' => $form_id,
      )));
    }
  }
  _hide_submit_inject();
}

//------------------------------------------------------------------------

//                        Private functions

//------------------------------------------------------------------------

/**
 * Insert JS into page.
 */
function _hide_submit_inject() {
  static $hide_submit_js_loaded = FALSE;
  if (!$hide_submit_js_loaded && _hide_submit_load_js_check_condition()) {
    $js = _hide_submit_get_javascript();
    drupal_add_js($js, 'inline', 'footer');
    $hide_submit_js_loaded = TRUE;
  }
}

/**
 * A recursive function to add class to all excluded submit buttons
 */
function _hide_submit_add_exclude_class(&$elements) {

  // Recurse through all children.
  foreach (element_children($elements) as $key) {
    if (isset($elements[$key]) && $elements[$key]) {
      _hide_submit_add_exclude_class($elements[$key]);
    }
  }

  // Add class to submit buttons
  if (isset($elements['#type']) && $elements['#type'] == 'submit') {
    $elements['#attributes']['class'] = empty($elements['#attributes']['class']) ? HIDE_SUBMIT_EXCLUDE_CLASS : $elements['#attributes']['class'] . ' ' . HIDE_SUBMIT_EXCLUDE_CLASS;
  }
}

/**
 * Check if JS should be loaded for current page
 */
function _hide_submit_load_js_check_condition() {
  $js_load_option = variable_get('hide_submit_js_load_option', HIDE_SUBMIT_DEFAULT_JS_LOAD);
  switch ($js_load_option) {
    case HIDE_SUBMIT_IN_ALL_PAGES:
      return TRUE;
    case HIDE_SUBMIT_IN_LISTED_PAGES:
    case HIDE_SUBMIT_EXCLUDE_LISTED_PAGES:
      $pages = variable_get('hide_submit_js_load_pages', '');
      break;
    case HIDE_SUBMIT_IN_CONTENT_ADD_EDIT:
    default:
      $pages = "node/add/*\r\nnode/*/edit";
      break;
  }
  if ($js_load_option != HIDE_SUBMIT_EXCLUDE_LISTED_PAGES) {
    $pages .= "\r\nadmin/settings/hide-submit";
  }
  $path = drupal_get_path_alias($_GET['q']);
  $regexp = '/^(' . preg_replace(array(
    '/(\\r\\n?|\\n)/',
    '/\\\\\\*/',
    '/(^|\\|)\\\\<front\\\\>($|\\|)/',
  ), array(
    '|',
    '.*',
    '\\1' . preg_quote(variable_get('site_frontpage', 'node'), '/') . '\\2',
  ), preg_quote($pages, '/')) . ')$/';

  // Compare with the internal and path alias (if any).
  $page_match = preg_match($regexp, $path);
  if ($path != $_GET['q']) {
    $page_match = $page_match || preg_match($regexp, $_GET['q']);
  }

  // Do we have a match on our page list?
  if ($js_load_option == HIDE_SUBMIT_EXCLUDE_LISTED_PAGES) {
    return !($page_match == 1);
  }
  return $page_match == 1;
}

/**
 * scrub the format strings for things that make bad javascript.
 *
 * @param $format_string
 * @return
 *   cleaned $format_string
 */
function _hide_submit_clean_for_javascript($format_string = '') {
  $patterns = array(
    '/\\n/',
    '/\\r/',
    '/\'/',
  );
  $replacements = array(
    '<br/>',
    '',
    '`',
  );
  return preg_replace($patterns, $replacements, $format_string);
}

/**
* get the image according to user selection, default, random etc...
*/
function _hide_submit_get_image() {

  // Use static to assure the same image is returned for the current page
  static $image = FALSE;
  if ($image !== FALSE) {
    return $image;
  }
  $image = variable_get('hide_submit_image', HIDE_SUBMIT_DEFAULT_IMAGE);
  if (is_array($image)) {
    list($usec, $sec) = explode(' ', microtime());
    srand((double) $sec + (double) $usec * 100000);
    $image = $image[rand() % count($image)];
  }
  return $image;
}

/**
 * Get javascript code for injection
 */
function _hide_submit_get_message() {
  global $language;
  $message = variable_get('hide_submit_message_' . $language->language, "");
  if ($message == "") {
    $message = variable_get('hide_submit_message', t("Please wait..."));
  }
  $image = _hide_submit_get_image();
  if ($image != "") {
    $image = theme('image', $image, $alt = '', $title = '', $attributes = NULL, $getsize = FALSE) . '&nbsp;';
  }
  return '<p class="hide_submit">' . $image . ' ' . $message . ' </p>';
}

/**
 * Get javascript code for injection
 */
function _hide_submit_get_javascript() {
  $message = filter_xss_admin(_hide_submit_clean_for_javascript(_hide_submit_get_message()));

  // Set base path for local image, none for external
  $image = _hide_submit_get_image();
  $image = url($image) == $image ? $image : base_path() . $image;
  $image = check_url($image);

  // Assemble jQuery selector
  $selector = 'input:submit:not(.' . HIDE_SUBMIT_EXCLUDE_CLASS . ')';
  $selector .= implode("", explode("\r\n", filter_xss_admin(variable_get('hide_submit_attribute_filter', ''))));

  // For debugging, this addtion to the script will paint included and excluded buttons
  $debug_code = _hide_submit_debug_on() ? "\$('input:submit').css({border:'6px red solid'}); \$('{$selector}').css({border:'6px green solid'});" : "";

  //background:'yellow',

  // Operation, hide or disable
  $operation = variable_get('hide_submit_script_mode', HIDE_SUBMIT_MODE_HIDE) == HIDE_SUBMIT_MODE_HIDE ? "\$(this).siblings('input:submit').hide(); \$(this).hide(); \$('{$message}').insertAfter(this); " : "\$(this).siblings('input:submit').attr('disabled', true); \$(this).attr('disabled', true);";
  $javascript = <<<JAVASCRIPT_CODE
jQuery("<img>").attr("src",'{<span class="php-variable">$image</span>}');
\$(document).ready(function() {
{<span class="php-variable">$debug_code</span>}
  \$('{<span class="php-variable">$selector</span>}').click(function() {
    {<span class="php-variable">$operation</span>}
  })
})
JAVASCRIPT_CODE;
  return $javascript;
}

/**
 * Debug mode check
 */
function _hide_submit_debug_on() {
  return variable_get('hide_submit_debug', FALSE) && user_access('administer site configuration');
}

Functions

Namesort descending Description
hide_submit_form_alter Implementation of hook_form_alter
hide_submit_help Implementation of hook_help().
hide_submit_menu Implementation of hook_menu
_hide_submit_add_exclude_class A recursive function to add class to all excluded submit buttons
_hide_submit_clean_for_javascript scrub the format strings for things that make bad javascript.
_hide_submit_debug_on Debug mode check
_hide_submit_get_image get the image according to user selection, default, random etc...
_hide_submit_get_javascript Get javascript code for injection
_hide_submit_get_message Get javascript code for injection
_hide_submit_inject Insert JS into page.
_hide_submit_load_js_check_condition Check if JS should be loaded for current page

Constants