You are here

ife.module in Inline Form Errors 7.2

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

Drupal hooks.

File

ife.module
View source
<?php

/**
 * @file
 * Drupal hooks.
 */
define('IFE_MESSAGE_DEFAULT', -1);
define('IFE_MESSAGE_LEAVE', 0);
define('IFE_MESSAGE_ALTERNATE', 1);
define('IFE_MESSAGE_REMOVE', 2);
define('IFE_POSITION_INLINE_MESSAGE_BEFORE', 0);
define('IFE_POSITION_INLINE_MESSAGE_AFTER', 1);
define('IFE_POSITION_INLINE_MESSAGE_CUSTOM', 2);

/**
 * Implements hook_menu().
 */
function ife_menu() {
  $items = array();
  $items['admin/config/user-interface/ife'] = array(
    'title' => 'Inline Form Errors',
    'description' => 'Administer which forms to use with field messages.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'ife_settings_form',
    ),
    'access arguments' => array(
      'administer inline form errors',
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'ife.settings.inc',
  );
  $items['admin/config/user-interface/ife/%ife_form_id/delete'] = array(
    'title' => 'Delete form_id',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'ife_form_id_delete_form',
      4,
    ),
    'access arguments' => array(
      'administer inline form errors',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'ife.settings.inc',
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function ife_permission() {
  return array(
    'administer inline form errors' => array(
      'title' => t('administer inline form errors'),
      'description' => t('Administer global Inline Form Errors settings and individual form conversions'),
    ),
  );
}

/**
 * Implements hook_help().
 */
function ife_help($path, $arg) {
  switch ($path) {
    case 'admin/help#ife':
      $output = '<p>' . t('IFE or Inline Form Errors allows you to place form submission error inline with the form elements. Three options are provided for setting your inline error behavior. You can configure the default behavior or override the behavior on a per form basis. You can add as many forms as you like.') . '</p>';
      $output .= '<p>' . t('IFE provides three behaviors for the configured forms') . '</p>';
      $output .= '<ul>';
      $output .= '<li>' . t('<strong>Leave the messages in place</strong>, this option will copy the error messages and place them inline. The original error messages set by Drupal will remain in place') . '</li>';
      $output .= '<li>' . t("<strong>Show an alternate message</strong>, this option will replace the original messages with a generic error message such as 'Please correct all errors.'. This message can be set in the IFE configuration page. The original error messages are placed inline with the form elements") . '</li>';
      $output .= '<li>' . t('<strong>Remove all messages</strong>, this option will remove all error messages and place them inline with the form element') . '</li>';
      $output .= '</ul>';
      $output .= '<p>' . t('In all cases only the messages related to the form will be touched. All other messages will remain in tact.') . '</p>';
      return $output;
    case 'admin/config/user-interface/ife':
      return '<p>' . t('This page provides the interface for adding new forms to use inline errors. Just add the form_id of the forms you wish to alter. An * can be used as a wildcard. The default settings can be overridden on a per form basis.') . '</p>';
  }
}

/**
 * Menu loader function to fetch a form id.
 */
function ife_form_id_load($form_id, $reset = FALSE) {
  $form_ids = ife_load_form_ids($reset);
  foreach ($form_ids as $form_id_pattern => $form_settings) {
    if (ife_match_form_id($form_id, $form_id_pattern)) {
      return $form_settings;
    }
  }
  return FALSE;
}

/**
 * Check if a form ID pattern matches a given form ID.
 *
 * @param string $form_id
 *   The form ID to compare the pattern to.
 * @param string $form_id_pattern
 *   A form ID pattern. Ex. webform_*.
 *
 * @return bool
 *   TRUE if the pattern matches the form_id, FALSE otherwise.
 */
function ife_match_form_id($form_id, $form_id_pattern) {

  // Convert form_id_pattern to a regular expression: replace /* with asterisks.
  $to_replace = array(
    '/\\\\\\*/',
  );
  $replacements = array(
    '.*',
  );

  // Quote regular expression characters.
  $form_id_pattern_quoted = preg_quote($form_id_pattern, '/');

  // Create regular expression.
  $form_id_pattern_regex = '/^(' . preg_replace($to_replace, $replacements, $form_id_pattern_quoted) . ')$/';
  return (bool) preg_match($form_id_pattern_regex, $form_id);
}

/**
 * Implements hook_theme().
 */
function ife_theme() {
  return array(
    'ife_settings_form_ids' => array(
      'render element' => 'form',
      'file' => 'ife.theme.inc',
    ),
    'ife_form_element' => array(
      'render element' => 'element',
      'file' => 'ife.theme.inc',
    ),
  );
}

/**
 * Load all form ids from the data base.
 */
function ife_load_form_ids($reset = FALSE) {
  ctools_include('export');
  static $form_ids;

  // Ensure that the schema cache is not stale when trying to load.
  $schema = drupal_get_schema('ife');
  if (!isset($schema['export']) || $reset) {
    ctools_export_load_object_reset('ife');
    drupal_get_schema('ife', TRUE);
  }

  // Load form settings.
  if (!isset($form_ids) || $reset) {
    $form_ids = ctools_export_load_object('ife');
  }
  return $form_ids;
}

/**
 * Helper function to determine the display settings of a form.
 */
function ife_form_id_display($form_id) {
  if ($form_id->display == IFE_MESSAGE_DEFAULT) {
    $display = variable_get('ife_display', IFE_MESSAGE_ALTERNATE);
  }
  else {
    $display = $form_id->display;
  }
  return $display;
}

/**
 * Implements hook_form_alter().
 */
function ife_form_alter(&$form, &$form_state, $form_id) {
  $status = variable_get('ife_show_everywhere', 0);
  if ($status && !in_array($form_id, _ife_blacklist())) {
    $ife_options = new stdClass();
    $ife_options->status = TRUE;
    $ife_options->display = -1;
  }
  else {
    $ife_options = ife_form_id_load($form_id);
  }
  if ($ife_options && $ife_options->status) {
    $display = ife_form_id_display($ife_options);
    $form['#ife_display'] = $display;

    // Commerce checkout.
    if (strpos($form_id, 'commerce_checkout_form') !== FALSE) {
      $form['buttons']['continue']['#validate'][] = 'ife_form_validator';
    }
    else {
      $form['#validate'][] = 'ife_form_validator';
    }
  }

  // Print form_ids.
  if (variable_get('ife_show_form_ids', 0)) {
    $form['ife_form_id'] = array(
      '#markup' => t('Form ID: @form_id', array(
        '@form_id' => $form_id,
      )),
      '#weight' => -1000,
      '#access' => user_access('administer inline form errors'),
    );
  }
}

/**
 * Return an array of core form ids that are not compatible with ife
 */
function _ife_blacklist() {
  return array(
    'menu_overview_form',
    'block_admin_display_form',
    'book_admin_edit',
    'filter_admin_order',
    'profile_admin_overview',
    'taxonomy_overview_terms',
    'node_form',
  );
}

/**
 * Custom form validation handler.
 */
function ife_form_validator(&$form, &$form_state) {
  static $global_error_processed = FALSE;

  // Commerce checkout.
  if (strpos($form['#form_id'], 'commerce_checkout_form') !== FALSE && isset($form_state['storage']['errors'])) {
    foreach ($form_state['storage']['errors'] as $name => $message) {
      form_set_error($name, $message);
    }
    unset($form_state['storage']['messages']);
  }
  $form_errors = form_get_errors();
  if (!empty($form_errors)) {
    ife_element_errors_set($form, $form['#ife_display']);
    if ($form['#ife_display'] == IFE_MESSAGE_ALTERNATE && !$global_error_processed) {
      $message = filter_xss_admin(variable_get('ife_general_message', 'Please correct all highlighted errors and try again.'));
      drupal_set_message($message, 'error');
      $global_error_processed = TRUE;
    }
  }

  // This function returns TRUE, because is does not really validate anything
  // and to support commerce modules this function needs to have a return value.
  return TRUE;
}

/**
 * General function to check if a form element has an error.
 * This function will then set the error on the element to be later used
 * by our theming function theme_ife_form_element().
 */
function ife_element_errors_set(&$element, $display, $carry_down = FALSE) {
  if (!isset($_SESSION['messages']['error'])) {
    return;
  }

  // Recurse through all children.
  foreach (element_children($element) as $key) {
    if (isset($element[$key]) && $element[$key]) {
      ife_element_errors_set($element[$key], $display, $carry_down);
    }
  }

  // Check for errors and settings.
  $errors = form_get_errors();
  if (!isset($element['#parents'])) {
    return;
  }
  $element_id = implode('][', $element['#parents']);
  if (!empty($errors[$element_id])) {
    $error_message = $errors[$element_id];

    // Get error id.
    $error_id = array_search($error_message, $_SESSION['messages']['error']);
    if ($error_id !== FALSE) {
      if (isset($display) && $display != IFE_MESSAGE_LEAVE) {
        unset($_SESSION['messages']['error'][$error_id]);
        $_SESSION['messages']['error'] = array_values($_SESSION['messages']['error']);
      }
      if (count($_SESSION['messages']['error']) <= 0) {
        unset($_SESSION['messages']['error']);
      }

      // Add error message to the element.
      $element['#ife_error'] = $error_message;

      // Add the position for the inline error message.
      $element['#ife_error_position'] = variable_get('ife_position_inline_message', IFE_POSITION_INLINE_MESSAGE_AFTER);

      // Add in our theme wrapper on the fly if it's not custom placement.
      if ($element['#ife_error_position'] != IFE_POSITION_INLINE_MESSAGE_CUSTOM) {
        if (!isset($element['#theme_wrappers']) || !in_array('ife_form_element', $element['#theme_wrappers'])) {
          $element['#theme_wrappers'][] = 'ife_form_element';
        }
      }

      // Found a matching error, no need to continue.
      return;
    }
  }
}

/**
 * Implements hook_schema_alter().
 *
 * Makes the ife table usable by ctools' export.inc.
 */
function ife_schema_alter(&$schema) {
  $schema['ife']['export'] = array(
    'key' => 'form_id',
    'primary key' => 'form_id',
    'identifier' => 'ife',
    'default hook' => 'ife_default_settings',
    'can disable' => FALSE,
    'api' => array(
      'owner' => 'ife',
      'api' => 'ife',
      'minimum_version' => 1,
      'current_version' => 1,
    ),
  );
}

Functions

Namesort descending Description
ife_element_errors_set General function to check if a form element has an error. This function will then set the error on the element to be later used by our theming function theme_ife_form_element().
ife_form_alter Implements hook_form_alter().
ife_form_id_display Helper function to determine the display settings of a form.
ife_form_id_load Menu loader function to fetch a form id.
ife_form_validator Custom form validation handler.
ife_help Implements hook_help().
ife_load_form_ids Load all form ids from the data base.
ife_match_form_id Check if a form ID pattern matches a given form ID.
ife_menu Implements hook_menu().
ife_permission Implements hook_permission().
ife_schema_alter Implements hook_schema_alter().
ife_theme Implements hook_theme().
_ife_blacklist Return an array of core form ids that are not compatible with ife

Constants