You are here

maxlength.module in Maxlength 6.2

Enables a max length countdown on node body, title and CCK textfields.

File

maxlength.module
View source
<?php

/**
 * @file
 *   Enables a max length countdown on node body, title and CCK textfields.
 */
define('MAXLENGTH_DEFAULT_TEXT', 'Content limited to !limit characters, remaining: <strong>!remaining</strong>');
define('MAXLENGTH_DEFAULT_USE_JS', TRUE);
define('MAXLENGTH_DEFAULT_LENGTH', 0);

/**
 * Implementation of hook_help().
 */
function maxlength_help($path, $arg) {
  switch ($path) {
    case 'admin/help#max_length_properties':
    case 'admin/modules#description':
      return t('Sets a maximum length for body fields and shows a counter that is updated as you type.');
      break;
  }
}

/**
 * Implementation of hook_form_alter().
 */
function maxlength_form_alter(&$form, &$form_state, $form_id) {

  // This is not ideal, but will allow anyone to use the #max_length_properties
  // element
  $form['#after_build'][] = 'maxlength_after_build';

  // Editing the content.
  if ($form['#id'] == 'node-form') {
    module_load_include('inc', 'maxlength');
    _maxlength_content_form_alter($form, $form_state, $form_id);
  }
  elseif ($form['#id'] == 'comment-form') {
    module_load_include('inc', 'maxlength');
    _maxlength_comment_form_alter($form, $form_state, $form_id);
  }
  elseif ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
    module_load_include('inc', 'maxlength');
    _maxlength_content_type_form_alter($form, $form_state, $form_id);
  }
  elseif ($form_id == 'content_field_edit_form') {
    module_load_include('inc', 'maxlength');
    if (_maxlength_is_supported_widget($form['#field']['widget']['type'])) {
      _maxlength_cck_form_alter($form, $form_state, $form_id);
    }
  }
  elseif ($form_id == 'content_field_remove_form') {
    $form['#submit'][] = 'maxlength_field_remove_submit';
  }
}

/**
 * Submit callback that removes the maxlength variables.
 */
function maxlength_field_remove_submit($form, &$form_state) {
  maxlength_remove_field_variables($form_state['values']['field_name']);
}

/**
 * Removes the variables for a field
 *
 * @param $field_name
 *   The machine fieldname of a field.
 */
function maxlength_remove_field_variables($field_name) {
  variable_del('maxlength_' . $field_name);
  variable_del('maxlength_' . $field_name . '_js');
  variable_del('maxlength_' . $field_name . '_text');
}

/**
 * Implementation of hook_node_type().
 */
function maxlength_node_type($op, $info) {
  $labels = array(
    'title',
    'js_title',
    'text_title',
    'body',
    'js_body',
    'text_body',
  );
  switch ($op) {
    case 'delete':
      foreach ($labels as $label) {
        variable_del('maxlength_' . $label . $info->type);
      }
      break;
    case 'update':
      if (!empty($info->old_type) && $info->old_type != $info->type) {
        foreach ($labels as $label) {
          $old_var = variable_get('maxlength_' . $label . $info->old_type, '');
          variable_set('maxlength_' . $label . $info->type, $old_var);
          variable_del('maxlength_' . $label . $info->old_type);
        }
      }
      break;
  }
}

/**
 * Finds all the elements in the form that request #max_length_properties behaviour
 * and respond. 
 */
function maxlength_after_build($element) {
  maxlength_recursive($element);
  return $element;
}

/**
 * Finds all the elements in the form that request #max_length_properties behaviour
 * and respond. 
 */
function maxlength_recursive(&$elements) {
  foreach (element_children($elements) as $key) {
    if (isset($elements[$key]) && $elements[$key]) {
      if (!empty($elements[$key]['#max_length_properties'])) {
        _maxlength_format_element($elements[$key]);
      }
      maxlength_recursive($elements[$key]);
    }
  }
}

/**
 * Formats a form element to use maxlength value and use js.
 * It's not moved to maxlength.inc because Form API calls it even when form_alter is not called
 *
 * @arg array $element
 *   The form element which should be maxlengthed.
 *
 */
function _maxlength_format_element(&$element) {
  static $js_added = FALSE;

  // Allow using a child element instead. The recurision will process
  // this later.
  if (!empty($element['#max_length_properties']['key'])) {
    if (!empty($element[$element['#max_length_properties']['key']])) {
      $element[$element['#max_length_properties']['key']]['#max_length_properties'] = $element['#max_length_properties'];
      unset($element[$element['#max_length_properties']['key']]['#max_length_properties']['key']);
      unset($element['#max_length_properties']);
    }
    return;
  }

  // Allow for a short hand method.
  if (!is_array($element['#max_length_properties'])) {
    $element['#max_length_properties'] = array(
      'limit' => $element['#max_length_properties'],
    );
  }

  // Set the default values.
  $element['#max_length_properties'] += array(
    'text' => MAXLENGTH_DEFAULT_TEXT,
    'use_js' => MAXLENGTH_DEFAULT_USE_JS,
    'value_key' => 'default_value',
  );

  // Add in validator.
  $element['#element_validate'][] = 'maxlength_validate_element';
  $values = $element['#max_length_properties'];
  if ($values['use_js']) {
    if (empty($js_added)) {
      $path = drupal_get_path('module', 'maxlength');
      drupal_add_js($path . '/maxlength.js');
      $js_added = TRUE;
    }
    $value = !empty($element[$values['value_key']]) ? $element[$values['value_key']] : '';
    $remaining = $values['limit'] - drupal_strlen($value);
    if ($remaining < 0) {
      drupal_set_message(t('%body_field_label truncated to %limit characters!', array(
        '%body_field_label' => $element['#title'],
        '%limit' => $values['limit'],
      )), 'error');
      $element[$values['value_key']] = drupal_substr($element['#default_value'], 0, $values['limit']);
      $remaining = 0;
    }

    // Make sure #id was set
    if (!isset($element['#id'])) {
      $element['#id'] = form_clean_id('edit-' . implode('-', $element['#parents']));
    }
    if (empty($element['#maxlength_processed'])) {
      $js_settings = array(
        'maxlength' => array(
          $element['#id'] => $values['limit'],
        ),
      );
      drupal_add_js($js_settings, 'setting');
      $element['#maxlength_processed'] = TRUE;
    }
    $element['#suffix'] = '<div id="maxlength-' . $element['#id'] . '"
      class="maxlength-counter">' . t($values['text'], array(
      '!limit' => $values['limit'],
      '!count' => '<span class="maxlength-count">' . drupal_strlen($value) . '</span>',
      '!remaining' => '<span class="maxlength-counter-remaining">' . $remaining . '</span>',
    )) . '</div>';
  }
}

/**
 * Element validate that checks the length of the text to see if it is valid.
 */
function maxlength_validate_element($element, &$form_state) {
  $text = $element['#value'];
  $text = str_replace("\r\n", '#', $text);
  $text = str_replace(array(
    "\n",
    "\r",
  ), '#', $text);
  if (drupal_strlen($text) > $element['#max_length_properties']['limit']) {
    form_error($element, t('!field has exceeded its maximum number of characters (!limit).', array(
      '!limit' => $element['#max_length_properties']['limit'],
      '!field' => $element['#title'],
    )));
  }
}

Functions

Namesort descending Description
maxlength_after_build Finds all the elements in the form that request #max_length_properties behaviour and respond.
maxlength_field_remove_submit Submit callback that removes the maxlength variables.
maxlength_form_alter Implementation of hook_form_alter().
maxlength_help Implementation of hook_help().
maxlength_node_type Implementation of hook_node_type().
maxlength_recursive Finds all the elements in the form that request #max_length_properties behaviour and respond.
maxlength_remove_field_variables Removes the variables for a field
maxlength_validate_element Element validate that checks the length of the text to see if it is valid.
_maxlength_format_element Formats a form element to use maxlength value and use js. It's not moved to maxlength.inc because Form API calls it even when form_alter is not called

Constants

Namesort descending Description
MAXLENGTH_DEFAULT_LENGTH
MAXLENGTH_DEFAULT_TEXT @file Enables a max length countdown on node body, title and CCK textfields.
MAXLENGTH_DEFAULT_USE_JS