1/* 2 * jQuery Textarea Counter Plugin 3 * Copyright (c) 2010 Roy Jin 4 * Copyright (c) 2013 LeadSift 5 * Version: 3.0 (11-APR-2013) 6 * http://www.opensource.org/licenses/mit-license.php 7 * Requires: jQuery v1.4.2 or later 8 */ 9(function($) { 10 $.fn.textareaCount = function(options, fn) { 11 var defaults = { 12 maxCharacterSize: -1 13 , truncate: true 14 , charCounter: 'standard' 15 , originalStyle: 'originalTextareaInfo' 16 , warningStyle: 'warningTextareaInfo' 17 , errorStyle: 'errorTextareaInfo' 18 , warningNumber: 20 19 , displayFormat: '#input characters | #words words' 20 } 21 , container = $(this) 22 , charLeftInfo 23 , numInput = 0 24 , maxCharacters = options.maxCharacterSize 25 , numLeft = 0 26 , numWords = 0 27 , charCounters = {} 28 ; 29 30 charCounters.standard = function(content){ 31 return content.length; 32 }; 33 34 charCounters.twitter = function(content){ 35 // function that counts urls as 22 chars 36 // regex to match various urls ... from http://stackoverflow.com/a/6427654 37 var url_length = 22 38 , replacement = Array(url_length+1).join("*") 39 , regex_str = "(https?:\/\/)?" + // SCHEME 40 "([a-z0-9+!*(),;?&=$_.-]+(:[a-z0-9+!*(),;?&=$_.-]+)?@)?" + // User and Pass 41 "([a-z0-9-.]*)\\.(travel|museum|[a-z]{2,4})" + // Host or IP 42 "(:[0-9]{2,5})?" + // Port 43 "(\/([a-z0-9+$_-]\\.?)+)*\/?" + // Path 44 "(\\?[a-z+&$_.-][a-z0-9;:@&%=+\/$_.-]*)?" + // GET Query 45 "(#[a-z_.-][a-z0-9+$_.-]*)?" // Anchor 46 , regex = new RegExp(regex_str, 'gi') 47 ; 48 return content.replace(regex, replacement).length; 49 }; 50 51 function getNewlineCount(content){ 52 var newlineCount = 0 53 , i; 54 for(i=0; i<content.length; i++){ 55 if(content.charAt(i) === '\n'){ 56 newlineCount++; 57 } 58 } 59 return newlineCount; 60 } 61 62 function formatDisplayInfo(){ 63 var format = options.displayFormat; 64 format = format.replace('#input', numInput); 65 format = format.replace('#words', numWords); 66 //When maxCharacters <= 0, #max, #left cannot be substituted. 67 if(maxCharacters > 0){ 68 format = format.replace('#max', maxCharacters); 69 format = format.replace('#left', numLeft); 70 } 71 return format; 72 } 73 74 function getInfo(){ 75 var info = { 76 input: numInput, 77 max: maxCharacters, 78 left: numLeft, 79 words: numWords 80 }; 81 return info; 82 } 83 84 function getNextCharLeftInformation(container){ 85 return container.next('.charleft'); 86 } 87 88 function isWin(){ 89 var strOS = navigator.appVersion; 90 if (strOS.toLowerCase().indexOf('win') !== -1){ 91 return true; 92 } 93 return false; 94 } 95 96 function getCleanedWordString(content){ 97 var fullStr = content + " " 98 , initial_whitespace_rExp = /^[^A-Za-z0-9]+/gi 99 , left_trimmedStr = fullStr.replace(initial_whitespace_rExp, "") 100 , non_alphanumerics_rExp = /[^A-Za-z0-9]+/gi 101 , cleanedStr = left_trimmedStr.replace(non_alphanumerics_rExp, " ") 102 , splitString = cleanedStr.split(" ") 103 ; 104 return splitString; 105 } 106 107 function countWord(cleanedWordString){ 108 var word_count = cleanedWordString.length-1; 109 return word_count; 110 } 111 112 function countByCharacters(){ 113 var content = container.val() 114 , lengthFunc = typeof(options.charCounter) === 'function'? options.charCounter : charCounters[options.charCounter] 115 , contentLength = lengthFunc(content) 116 , newlineCount 117 , systemmaxCharacterSize 118 , originalScrollTopPosition 119 ; 120 121 // Start Cut 122 if(options.maxCharacterSize > 0){ 123 // If copied content is already more than maxCharacterSize, 124 // chop it to maxCharacterSize only if truncate is true 125 if(options.truncate && contentLength >= options.maxCharacterSize) { 126 content = content.substring(0, options.maxCharacterSize); 127 } 128 129 newlineCount = getNewlineCount(content); 130 131 systemmaxCharacterSize = options.maxCharacterSize; 132 if (isWin()){ 133 // newlineCount new line character. For windows, it occupies 2 characters 134 systemmaxCharacterSize = options.maxCharacterSize - newlineCount; 135 } 136 if(options.truncate && contentLength > systemmaxCharacterSize){ 137 //avoid scroll bar moving 138 originalScrollTopPosition = this.scrollTop; 139 container.val(content.substring(0, systemmaxCharacterSize)); 140 this.scrollTop = originalScrollTopPosition; 141 } 142 charLeftInfo.removeClass(options.warningStyle + ' ' + options.errorStyle); 143 if(systemmaxCharacterSize - contentLength <= options.warningNumber){ 144 charLeftInfo.addClass(options.warningStyle); 145 } 146 if(systemmaxCharacterSize - contentLength < 0){ 147 charLeftInfo.addClass(options.errorStyle); 148 } 149 150 numInput = contentLength; 151 if(isWin()){ 152 numInput = contentLength + newlineCount; 153 } 154 155 numWords = countWord(getCleanedWordString(container.val())); 156 157 numLeft = maxCharacters - numInput; 158 } else { 159 //normal count, no cut 160 newlineCount = getNewlineCount(content); 161 numInput = contentLength; 162 if(isWin()){ 163 numInput = contentLength + newlineCount; 164 } 165 numWords = countWord(getCleanedWordString(container.val())); 166 } 167 168 return formatDisplayInfo(); 169 } 170 171 function limitTextAreaByCharacterCount(){ 172 charLeftInfo.html(countByCharacters()); 173 //function call back 174 if(typeof fn !== 'undefined'){ 175 fn.call(this, getInfo()); 176 } 177 return true; 178 } 179 180 options = $.extend(defaults, options); 181 $("<div class='charleft'> </div>").insertAfter(container); 182 charLeftInfo = getNextCharLeftInformation(container); 183 charLeftInfo.addClass(options.originalStyle); 184 185 limitTextAreaByCharacterCount(); 186 187 container.bind('keyup', function(){ 188 limitTextAreaByCharacterCount();} 189 ).bind('mouseover paste', function(){ 190 setTimeout(function(){ 191 limitTextAreaByCharacterCount(); 192 }, 10); 193 }); 194 }; 195})(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.