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