Index: maxlength/maxlength.inc =================================================================== --- maxlength/maxlength.inc (revision 737) +++ maxlength/maxlength.inc (revision 749) @@ -10,3 +10,7 @@ // Permissions define('ADMINISTER_MAXLENGTH', 'administer maxlength'); + +// Types of limits +define('LIMIT_CHAR', 'char'); +define('LIMIT_WORD', 'word'); Index: maxlength/maxlength.js =================================================================== --- maxlength/maxlength.js (revision 737) +++ maxlength/maxlength.js (revision 749) @@ -2,14 +2,29 @@ Drupal.maxLength_limit = function (field) { var limit = field.attr("limit"); + var limitType = field.attr("limit_type"); // calculate the remaining count of chars - var remainingCnt = limit - field.val().length; + var remainingCnt = 0; + if (limitType == 'char') { + remainingCnt = limit - field.val().length; + } + else if (limitType == 'word') { + var trimmed = field.val().replace(/^\s+|\s+$/g, ''); + if (trimmed.length == 0) { // required as .split() on empty string returns 1-element array + remainingCnt = limit; + } + else { + remainingCnt = limit - trimmed.split(/\s+/).length; + } + } // if there is not remaining char, we clear additional content if (remainingCnt < 0) { - field.val(field.val().substr(0, limit)); - remainingCnt = 0; + if (limitType == 'char') { + field.val(field.val().substr(0, limit)); + remainingCnt = 0; + } } // update the remaing chars text @@ -17,17 +32,18 @@ } Drupal.maxLength_change = function () { - var element = $(this); - Drupal.maxLength_limit($(this), $(this).attr("limit")); + Drupal.maxLength_limit($(this)); } if (Drupal.jsEnabled) { $(document).ready(function(){ - // get all the settings, and save the limits in the fields + // get all the settings, and save the limits and limit types in the fields for (var id in Drupal.settings.maxlength) { var limit = Drupal.settings.maxlength[id]; + var limitType = Drupal.settings.limit_type[id]; var element = $("#"+ id); element.attr("limit", limit); + element.attr("limit_type", limitType); // update the count at the page load Drupal.maxLength_limit(element); Index: maxlength/maxlength.module =================================================================== --- maxlength/maxlength.module (revision 737) +++ maxlength/maxlength.module (revision 749) @@ -35,6 +35,7 @@ if ($form['#id'] == 'node-form') { _maxlength_content_form_alter($form, $form_state, $form_id); } + // Editing the content type elseif ($form_id == 'node_type_form' && isset($form['identity']['type'])) { _maxlength_content_type_form_alter($form, $form_state, $form_id); @@ -48,6 +49,7 @@ // Deleting a CCK text field. elseif ($form_id == '_content_admin_field_remove') { variable_del(MAXLENGTH_NODE_TYPE . $form['field_name']['#value']); + variable_del(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_type'); variable_del(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_js'); variable_del(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_text'); } @@ -56,12 +58,11 @@ function _maxlength_content_form_alter(&$form, &$form_state, $form_id) { $type = $form['type']['#value']; // update the title as needed - _maxlength_format_element($form['title'], $form['title']['#default_value'], 'title', 'title', $type); + _maxlength_format_element($form['title'], 'title', 'title', $type); // Update the body as needed - _maxlength_format_element($form['body_field']['body'], $form['body_field']['body']['#default_value'], 'body', 'body', $type); + _maxlength_format_element($form['body_field']['body'], 'body', 'body', $type); - if (module_exists('content')) { // Get a list of all the CCK fields for this content type $list = array_keys(content_fields(NULL, $type)); @@ -70,7 +71,7 @@ foreach ($list as $field) { if (is_array($form[$field])) { foreach (element_children($form[$field]) as $key) { - _maxlength_format_element($form[$field][$key], $form[$field][$key]['value'], $field, str_replace('_', '-', $field) .'-'. $key .'-value', $type); + _maxlength_format_element($form[$field][$key], $field, str_replace('_', '-', $field) .'-'. $key .'-value', $type); } } } @@ -97,23 +98,32 @@ $form['submission'][MAXLENGTH_NODE_TYPE . $label][MAXLENGTH_NODE_TYPE . $label] = array( '#type' => 'textfield', '#title' => t('!label max length', array('!label' => ucwords($label))), - '#field_suffix' => t('characters'), '#return_value' => 1, '#size' => 4, '#default_value' => variable_get(MAXLENGTH_NODE_TYPE . $label .'_'. $type, ''), - '#description' => t('Maximum number of characters allowed for the !type field of this content type. Leave blank for an unlimited size.', array('!type' => $label)) .'
'. - ''. t('Please remember, it counts all characters, including HTML, so may not work as expected with rich text editors e.g. FCKeditor / tinyMCE.') .'', - ); + '#description' => t('Maximum number of characters or words allowed for the !type field of this content type. Leave blank for an unlimited size.', array('!type' => $label)) .'
'. + ''. t('Please remember, it counts all characters/words, including HTML, so may not work as expected with rich text editors e.g. FCKeditor / tinyMCE.') .'', + ); + + $form['submission'][MAXLENGTH_NODE_TYPE . $label][MAXLENGTH_NODE_TYPE . $label .'_type'] = array( + '#type' => 'select', + '#title' => t('!label Limit Type', array('!label' => ucwords($label))), + '#options' => array(LIMIT_CHAR => t('Characters'), LIMIT_WORD => t('Words')), + '#default_value' => variable_get(MAXLENGTH_NODE_TYPE . $label .'_type_'. $type, ''), + '#description' => t('Choose whether to limit the title field size by characters or words.'), + ); + $form['submission'][MAXLENGTH_NODE_TYPE . $label][MAXLENGTH_NODE_TYPE . $label .'_js'] = array( '#type' => 'checkbox', - '#title' => t('Enable remaining characters countdown for the !label', array('!label' => ucwords($label))), + '#title' => t('Enable remaining characters/words countdown for the !label', array('!label' => ucwords($label))), '#default_value' => variable_get(MAXLENGTH_NODE_TYPE . $label .'_js_'. $type, '0'), '#description' => t('This will enable a Javascript based count down, as well as the client side validation for the !type field of this content type. If no limit set this is ignored.', array('!type' => $label)), ); + $form['submission'][MAXLENGTH_NODE_TYPE . $label][MAXLENGTH_NODE_TYPE . $label .'_text'] = array( '#type' => 'textarea', '#title' => t('!label count down message', array('!label' => ucwords($label))), - '#default_value' => variable_get(MAXLENGTH_NODE_TYPE . $label .'_text_'. $type, 'Content limited to !limit characters, remaining: !remaining'), + '#default_value' => variable_get(MAXLENGTH_NODE_TYPE . $label .'_text_'. $type, 'Content limited to !limit characters/words, remaining: !remaining'), '#description' => t('The text used in the Javascript message under the !type input, where "!limit" and "!remaining" are replaced by the appropriate numbers.', array('!type' => $label)), ); } @@ -126,9 +136,17 @@ foreach ($form['field'] as $key => $field) { $new_fields[$key] = $field; if ($key == 'max_length') { + $new_fields[MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_type'] = array( + '#type' => 'select', + '#title' => t('!label Limit Type', array('!label' => ucwords($form['field_name']['#value']))), + '#options' => array('char' => t('Characters'), 'word' => t('Words')), + '#default_value' => variable_get(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_type', ''), + '#description' => t('Choose whether to limit the title field size by characters or words.'), + ); + $new_fields[MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_js'] = array( '#type' => 'checkbox', - '#title' => t('Enable remaining characters countdown for this field'), + '#title' => t('Enable remaining characters/words countdown for this field'), '#default_value' => variable_get(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_js', '0'), '#description' => t('This will enable a Javascript based count down, as well as the client side validation for this field. If no limit set this is ignored.'), ); @@ -136,7 +154,7 @@ $new_fields[MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_text'] = array( '#type' => 'textarea', '#title' => t('Count down message'), - '#default_value' => variable_get(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_text', 'Content limited to !limit characters, remaining: !remaining'), + '#default_value' => variable_get(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_text', 'Content limited to !limit characters/words, remaining: !remaining'), '#description' => t('The text used in the Javascript message under the input, where "!limit" and "!remaining" are replaced by the appropriate numbers.'), ); } @@ -149,6 +167,7 @@ function _maxlength_cck_form_submit($form, &$form_state) { //note, max lenght for the CCK field is stored in this way as for textareas, its not in $element var passed to theme functions. variable_set(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'], $form['#post']['max_length']); + variable_set(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_type', $form['#post'][MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_type']); variable_set(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_js', $form['#post'][MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_js']); variable_set(MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_text', $form['#post'][MAXLENGTH_NODE_TYPE . $form['field_name']['#value'] .'_text']); } @@ -172,37 +191,29 @@ * Could this all be done without drupal_add_js and just theming of the form element. * Can we use a theme function to let alter the placement of the maxlength text. */ -function _maxlength_format_element(&$element, $value = '', $field, $id, $type = '') { +function _maxlength_format_element(&$element, $field, $id, $type = '') { $values = _maxlength_get_values($field, $type); if ($values !== FALSE AND isset($values['limit']) AND $values['limit'] AND $values['use_js']) { $path = drupal_get_path('module', 'maxlength'); drupal_add_js($path .'/maxlength.js'); - $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['#default_value'] = drupal_substr($element['#default_value'], 0, $values['limit']); - $remaining = 0; - } - $js_settings = array( 'maxlength' => array( 'edit-'. $id => $values['limit'], ), + 'limit_type' => array( + 'edit-'. $id => $values['type'], + ), ); drupal_add_js($js_settings, 'setting'); - $element['#suffix'] = '
'. t($values['text'], array('!limit' => $values['limit'], '!remaining' => ''. $remaining .'')) .'
'; + + $element['#suffix'] = '
'. + t($values['text'], + array('!limit' => $values['limit'], + '!remaining' => '', + ) + ) .'
'; } } @@ -213,11 +224,13 @@ //CCK if (strpos($field, 'field_') === 0) { $values['limit'] = variable_get(MAXLENGTH_NODE_TYPE . $field, FALSE); + $values['type'] = variable_get(MAXLENGTH_NODE_TYPE . $field .'_type', FALSE); $values['use_js'] = variable_get(MAXLENGTH_NODE_TYPE . $field .'_js', FALSE); $values['text'] = variable_get(MAXLENGTH_NODE_TYPE . $field .'_text', FALSE); } //body and title elseif ($type != '') { $values['limit'] = variable_get(MAXLENGTH_NODE_TYPE . $field .'_'. $type, FALSE); + $values['type'] = variable_get(MAXLENGTH_NODE_TYPE . $field .'_type_'. $type, FALSE); $values['use_js'] = variable_get(MAXLENGTH_NODE_TYPE . $field .'_js_'. $type, FALSE); $values['text'] = variable_get(MAXLENGTH_NODE_TYPE . $field .'_text_'. $type, FALSE); } @@ -242,14 +255,18 @@ foreach ($fields as $field) { $limit = intval(variable_get(MAXLENGTH_NODE_TYPE . $field .'_'. $node->type, '')); if ($limit > 0) { + $type = variable_get(MAXLENGTH_NODE_TYPE . $field .'_type_'. $node->type, ''); switch ($op) { case 'validate': $form = $a3; - if (drupal_strlen($node->$field) > $limit) { + if ($type == LIMIT_CHAR && drupal_strlen($node->$field) > $limit) { form_set_error($field, t('The !field field has exceeded its maximum number of characters (!limit).', array('!limit' => $limit, '!field' => $field))); } + elseif ($type == LIMIT_WORD && _maxlength_count_words($node->$field) > $limit) { + form_set_error($field, t('The !field field has exceeded its maximum number of words (!limit).', array('!limit' => $limit, '!field' => $field))); + } break; - } + } } } } @@ -259,8 +276,8 @@ */ function maxlength_node_type($op, $info) { $labels = array( - 'title', 'js_title', 'text_title', - 'body', 'js_body', 'text_body'); + 'title', 'type_title', 'js_title', 'text_title', + 'body', 'type_body', 'js_body', 'text_body'); switch ($op) { case 'delete': @@ -277,8 +294,14 @@ variable_del(MAXLENGTH_NODE_TYPE . $label . $info->old_type); } } - break; } } +function _maxlength_count_words($value) { + if (drupal_strlen(trim($value)) == 0) { // required as preg_split() on empty string returns 1-element array + return 0; + } + + return count(preg_split('/\s+/', trim($value))); +} Index: maxlength/maxlength.install =================================================================== --- maxlength/maxlength.install (revision 737) +++ maxlength/maxlength.install (revision 749) @@ -57,8 +57,8 @@ */ function maxlength_uninstall() { foreach (node_get_types() as $type => $name) { - $labels = array('title', 'js_title', 'text_title', - 'body', 'js_body', 'text_body'); + $labels = array('title', 'type_title','js_title', 'text_title', + 'body', 'type_body','js_body', 'text_body'); foreach ($labels as $label) { variable_del(MAXLENGTH_NODE_TYPE . $label . $type);