├── README.md ├── demo.html ├── jquery.simplyCountable.js └── simplyCountable.jquery.json /README.md: -------------------------------------------------------------------------------- 1 | # jQuery Simply Countable plugin 2 | 3 | jQuery plugin that provides a character counter for any text input or textarea. Works when typing and pasting text using the mouse. 4 | 5 | * version - 0.5.0 6 | * homepage - [http://github.com/aaronrussell/jquery-simply-countable/](http://github.com/aaronrussell/jquery-simply-countable/) 7 | * author - [Aaron Russell](http://www.aaronrussell.co.uk) 8 | 9 | ## Usage 10 | 11 | Simple usage: 12 | 13 | $('#my_textarea').simplyCountable(); 14 | 15 | Advanced usage: 16 | 17 | $('#my_textarea').simplyCountable({ 18 | counter: '#counter', 19 | countType: 'characters', 20 | maxCount: 140, 21 | strictMax: false, 22 | countDirection: 'down', 23 | safeClass: 'safe', 24 | overClass: 'over', 25 | thousandSeparator: ',', 26 | onOverCount: function(count, countable, counter){}, 27 | onSafeCount: function(count, countable, counter){}, 28 | onMaxCount: function(count, countable, counter){} 29 | }); 30 | 31 | ## Options 32 | 33 | * `counter` - A jQuery selector to match the 'counter' element. Defaults to `#counter`. 34 | * `countType` - Select whether to count `characters` or `words`. Defaults to `characters`. 35 | * `maxCount` - The maximum character (or word) count of the text input or textarea. Defaults to `140`. 36 | * `strictMax` - Prevents the user from being able to exceed the `maxCount`. Defaults to `false`. 37 | * `countDirection` - Select whether to count `down` or `up`. Defaults to `down`. 38 | * `safeClass` - The CSS class applied to the counter element when it is within the maxCount figure. Defaults to `safe`. 39 | * `overClass` - The CSS class applied to the counter element when it exceeds the maxCount figure. Defaults to `over`. 40 | * `thousandSeparator` - The separator for multiples of 1,000. Set to `false` to disable. Defaults to `,`. 41 | * `onOverCount` - Callback function called when counter goes over `maxCount` figure. 42 | * `onSafeCount` - Callback function called when counter goes below `maxCount` figure. 43 | * `onMaxCount` - Callback function called when in `strictMax` mode and counter hits `maxCount` figure. 44 | 45 | ## License 46 | 47 | Dual licensed under the [MIT](http://www.opensource.org/licenses/mit-license.php) and [GPL](http://www.opensource.org/licenses/gpl-license.php) licenses. 48 | 49 | Copyright (c) 2009-2013 [Aaron Russell](http://www.aaronrussell.co.uk). -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |Copyright © 2009-2013 Aaron Russell. 55 | 56 | -------------------------------------------------------------------------------- /jquery.simplyCountable.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Simply Countable plugin 3 | * Provides a character counter for any text input or textarea 4 | * 5 | * @version 0.4.2 6 | * @homepage http://github.com/aaronrussell/jquery-simply-countable/ 7 | * @author Aaron Russell (http://www.aaronrussell.co.uk) 8 | * 9 | * Copyright (c) 2009-2010 Aaron Russell (aaron@gc4.co.uk) 10 | * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 11 | * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 12 | */ 13 | 14 | (function($){ 15 | 16 | $.fn.simplyCountable = function(options){ 17 | 18 | options = $.extend({ 19 | counter: '#counter', 20 | countType: 'characters', 21 | maxCount: 140, 22 | strictMax: false, 23 | countDirection: 'down', 24 | safeClass: 'safe', 25 | overClass: 'over', 26 | thousandSeparator: ',', 27 | onOverCount: function(){}, 28 | onSafeCount: function(){}, 29 | onMaxCount: function(){} 30 | }, options); 31 | 32 | var navKeys = [33,34,35,36,37,38,39,40]; 33 | 34 | return $(this).each(function(){ 35 | 36 | var countable = $(this); 37 | var counter = $(options.counter); 38 | if (!counter.length) { return false; } 39 | 40 | var countCheck = function(){ 41 | 42 | var count; 43 | var revCount; 44 | 45 | var reverseCount = function(ct){ 46 | return ct - (ct*2) + options.maxCount; 47 | } 48 | 49 | var countInt = function(){ 50 | return (options.countDirection === 'up') ? revCount : count; 51 | } 52 | 53 | var numberFormat = function(ct){ 54 | var prefix = ''; 55 | if (options.thousandSeparator){ 56 | ct = ct.toString(); 57 | // Handle large negative numbers 58 | if (ct.match(/^-/)) { 59 | ct = ct.substr(1); 60 | prefix = '-'; 61 | } 62 | for (var i = ct.length-3; i > 0; i -= 3){ 63 | ct = ct.substr(0,i) + options.thousandSeparator + ct.substr(i); 64 | } 65 | } 66 | return prefix + ct; 67 | } 68 | 69 | var changeCountableValue = function(val){ 70 | countable.val(val).trigger('change'); 71 | } 72 | 73 | /* Calculates count for either words or characters */ 74 | if (options.countType === 'words'){ 75 | count = options.maxCount - $.trim(countable.val()).split(/\s+/).length; 76 | if (countable.val() === ''){ count += 1; } 77 | } 78 | else { count = options.maxCount - countable.val().length; } 79 | revCount = reverseCount(count); 80 | 81 | /* If strictMax set restrict further characters */ 82 | if (options.strictMax && count <= 0){ 83 | var content = countable.val(); 84 | if (count < 0) { 85 | options.onMaxCount(countInt(), countable, counter); 86 | } 87 | if (options.countType === 'words'){ 88 | var allowedText = content.match( new RegExp('\\s?(\\S+\\s+){'+ options.maxCount +'}') ); 89 | if (allowedText) { 90 | changeCountableValue(allowedText[0]); 91 | } 92 | } 93 | else { changeCountableValue(content.substring(0, options.maxCount)); } 94 | count = 0, revCount = options.maxCount; 95 | } 96 | 97 | counter.text(numberFormat(countInt())); 98 | 99 | /* Set CSS class rules and API callbacks */ 100 | if (!counter.hasClass(options.safeClass) && !counter.hasClass(options.overClass)){ 101 | if (count < 0){ counter.addClass(options.overClass); } 102 | else { counter.addClass(options.safeClass); } 103 | } 104 | else if (count < 0 && counter.hasClass(options.safeClass)){ 105 | counter.removeClass(options.safeClass).addClass(options.overClass); 106 | options.onOverCount(countInt(), countable, counter); 107 | } 108 | else if (count >= 0 && counter.hasClass(options.overClass)){ 109 | counter.removeClass(options.overClass).addClass(options.safeClass); 110 | options.onSafeCount(countInt(), countable, counter); 111 | } 112 | 113 | }; 114 | 115 | countCheck(); 116 | 117 | countable.on('keyup blur paste', function(e) { 118 | switch(e.type) { 119 | case 'keyup': 120 | // Skip navigational key presses 121 | if ($.inArray(e.which, navKeys) < 0) { countCheck(); } 122 | break; 123 | case 'paste': 124 | // Wait a few miliseconds if a paste event 125 | setTimeout(countCheck, (e.type === 'paste' ? 5 : 0)); 126 | break; 127 | default: 128 | countCheck(); 129 | break; 130 | } 131 | }); 132 | 133 | }); 134 | 135 | }; 136 | 137 | })(jQuery); -------------------------------------------------------------------------------- /simplyCountable.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplyCountable", 3 | "version": "0.5.0", 4 | "title": "jQuery Simply Countable", 5 | "description": "jQuery plugin that provides a character counter for any text input or textarea.", 6 | "author": { 7 | "name": "Aaron Russell", 8 | "url": "http://aaronrussell.co.uk" 9 | }, 10 | "keywords": [ 11 | "forms", 12 | "input", 13 | "textarea", 14 | "counter" 15 | ], 16 | "dependencies": { 17 | "jquery": ">=1.4" 18 | }, 19 | "licenses": [ 20 | { 21 | "type": "MIT", 22 | "url": "http://www.opensource.org/licenses/mit-license.php" 23 | }, 24 | { 25 | "type": "GPL", 26 | "url": "http://www.opensource.org/licenses/gpl-license.php" 27 | } 28 | ], 29 | "homepage": "https://github.com/aaronrussell/jquery-simply-countable", 30 | "bugs": "https://github.com/aaronrussell/jquery-simply-countable/issues" 31 | } --------------------------------------------------------------------------------