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 ([email protected]) 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);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.