Skip to content

Instantly share code, notes, and snippets.

@bfncs
Created December 11, 2012 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bfncs/4258927 to your computer and use it in GitHub Desktop.
Save bfncs/4258927 to your computer and use it in GitHub Desktop.
TextArea Counter for Processwire

Textarea Counter for Processwire

What it does

The module adds a possibility to define a character/word limit to textarea inputs in Processwire. It will show a live count when editing these fields.

Installation

Just drop the files TextAreaCounter.module and TextAreaCounter.js in a folder called TextAreaCounter in your site's modules directory. Install from the backend as used to.

How to use it

To use it with a specific Textarea input field, edit the desired input in the backend and add a limit for characters and/or words. You should be ready to go.

Credit

Most of the code was helpfully provided by Soma in the Processwire forums.

Still missing

  • Proper documentation
  • A mechanism to (optionally) prevent the user from saving texts that are too long
  • An expansion to bring this functionality to flat text inputs as well.
(function ($) {
var checkWordLimit = function (elem) {
console.log('recalc');
var count = elem.attr('data-maxwords') - elem.val().split(/\s+/).length;
elem.parent().find("span.counterWords span").text(count);
};
$(document).ready(function () {
$('textarea[data-maxchars]').each(function () {
var $this = $(this);
var $span = $this.parent().find("span.counterChars span");
$this.bind("keyup change", function() {
var count = $this.attr('data-maxchars') - $this.val().replace(/\r?\n/g, '\r\n').length;
$span.text(count);
});
});
$('textarea[data-maxwords]').each(function () {
var $this = $(this);
var $span = $this.parent().find("span.counterWords span");
$this.bind("keyup change", function () {
var count = $this.attr('data-maxwords') - $this.val().split(/\s+/).length;
$span.text(count);
});
});
});
}(jQuery));
<?php
class TextAreaCounter extends WireData implements Module {
/**
* getModuleInfo is a module required by all modules to tell ProcessWire about them
*
* @return array
*
*/
public static function getModuleInfo() {
return array(
'title' => 'Textarea Counter',
'version' => 1,
'summary' => 'Proof of concept. Counts chars in a textarea',
'href' => '',
'singular' => true,
'autoload' => true
);
}
public function init() {
$this->addHookAfter('InputfieldTextarea::getConfigInputfields', $this, 'hookAddConfig');
$this->addHookBefore('InputfieldTextarea::render', $this, 'renderBeforeTextarea');
$this->addHookAfter('InputfieldTextarea::render', $this, 'renderTextarea');
}
public function hookAddConfig(HookEvent $event) {
// not tinymce fields
if($event->object == 'InputfieldTinyMCE') return;
// get inputfields from getConfigInputfields
$inputfields = $event->return;
// add maxchars setting
$f = $this->modules->get('InputfieldInteger');
$f->label = $this->_('Max. characters');
$f->description = $this->_('The maximum amount of characters that can be entered.');
$f->attr('name','maxchars');
$value = $this->fields->get($event->object->name)->maxchars;
$f->attr('value', $value ? $value : '');
$inputfields->append($f);
$f = $this->modules->get('InputfieldInteger');
$f->label = $this->_('Max. words');
$f->description = $this_('The maximum amount of words that can be entered.');
$f->attr('name','maxwords');
$value = $this->fields->get($event->object->name)->maxwords;
$f->attr('value', $value ? $value : '');
$inputfields->append($f);
}
public function renderBeforeTextarea(HookEvent $event){
// only on page edits screens
if($this->process != 'ProcessPageEdit') return;
$field = $event->object;
// no tinymce fields
if($field == 'InputfieldTinyMCE') return;
// get field to set attribute, will get rendered by the InputfieldTexarea
$inputfield = $this->fields->get($field->name);
$types = array(
'chars',
'words'
);
foreach ($types as $type) {
$max = $this->fields->get($event->object->name)->{'max'.$type};
if ($max && 0 < intval($max)) {
$field->attr('data-max'.$type, $inputfield->{'max'.$type});
}
}
}
public function renderTextarea(HookEvent $event){
// add stuff only to admin pages edit screen
if($this->process != 'ProcessPageEdit') return;
// not render span if tinymce field
if($event->object == 'InputfieldTinyMCE') return;
$labels = array(
'chars' => $this->_('Characters left'),
'words' => $this->_('Words left')
);
$append = array();
$value = $event->object->value;
foreach ($labels as $type => $label) {
$max = $this->fields->get($event->object->name)->{'max'.$type};
if ($max && 0 < intval($max)) {
$left = $max - $this->{'count'.ucfirst($type)}($value);
$append[] = '<span class="counter'.ucfirst($type).'">'.$label.': <span class="counterVal">'.$left.'</span></span>';
}
}
if (0 < count($append)) {
// render counter spans after text field
$event->return .= implode(' ', $append);
// add scripts to admin page
$this->config->scripts->add($this->config->urls->TextAreaCounter . 'TextAreaCounter.js');
}
}
private function countChars($str) {
return strlen($str);
}
private function countWords($str) {
return count(preg_split('/\s+/', $str));
}
}
@danielcgold
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment