hjg
2024-10-30 8cf23534166c07e711aac2a25911ada317ba01f0
提交 | 用户 | 时间
58d006 1 /* ==========================================================
A 2  * bootstrap-maxlength.js v1.4.2
3  * 
4  * Copyright (c) 2013 Maurizio Napoleoni; 
5  *
6  * Licensed under the terms of the MIT license.
7  * See: https://github.com/mimo84/bootstrap-maxlength/blob/master/LICENSE
8  * ========================================================== */
9 /*jslint browser:true*/
10 /*global  jQuery*/
11 (function ($) {
12     "use strict";
13
14     $.fn.extend({
15         maxlength: function (options, callback) {
16
17             var documentBody = $('body'),
18                 defaults = {
19                     alwaysShow: false, // if true the indicator it's always shown.
20                     threshold: 10, // Represents how many chars left are needed to show up the counter
21                     warningClass: "label label-success",
22                     limitReachedClass: "label label-important",
23                     separator: ' / ',
24                     preText: '',
25                     postText: '',
26                     showMaxLength : true,
27                     placement: 'bottom',
28                     showCharsTyped: true, // show the number of characters typed and not the number of characters remaining
29                     validate: false, // if the browser doesn't support the maxlength attribute, attempt to type more than
30                                                                         // the indicated chars, will be prevented.
31                     utf8: false // counts using bytesize rather than length.  eg: '£' is counted as 2 characters.
32                 };
33
34             if ($.isFunction(options) && !callback) {
35                 callback = options;
36                 options = {};
37             }
38             options = $.extend(defaults, options);
39
40           /**
41           * Return the length of the specified input.
42           *
43           * @param input
44           * @return {number}
45           */
46             function inputLength(input) {
47               var text = input.val();
48               var matches = text.match(/\n/g);
49
50               var breaks = 0;
51               var inputLength = 0;
52
53               if (options.utf8) {
54                 breaks = matches ? getUTF8Length(matches) : 0;
55                 inputLength = getUTF8Length(input.val()) + breaks;
56               } else {
57                 breaks = matches ? matches.length : 0;
58                 inputLength = input.val().length + breaks;
59               }
60               return inputLength;
61             }
62
63           /**
64           * Return the length of the specified input in UTF8 encoding.
65           *
66           * @param input
67           * @return {number}
68           */
69             function utf8Length(string) {
70               var utf8length = 0;
71               for (var n = 0; n < string.length; n++) {
72                 var c = string.charCodeAt(n);
73                 if (c < 128) {
74                   utf8length++;
75                 }
76                 else if((c > 127) && (c < 2048)) {
77                   utf8length = utf8length+2;
78                 }
79                 else {
80                   utf8length = utf8length+3;
81                 }
82               }
83               return utf8length;
84             }
85
86           /**
87            * Return true if the indicator should be showing up.
88            *
89            * @param input
90            * @param thereshold
91            * @param maxlength
92            * @return {number}
93            */
94             function charsLeftThreshold(input, thereshold, maxlength) {
95                 var output = true;
96                 if (!options.alwaysShow && (maxlength - inputLength(input) > thereshold)) {
97                     output = false;
98                 }
99                 return output;
100             }
101
102           /**
103            * Returns how many chars are left to complete the fill up of the form.
104            *
105            * @param input
106            * @param maxlength
107            * @return {number}
108            */
109             function remainingChars(input, maxlength) {
110                 var length = maxlength - inputLength(input);
111                 return length;
112             }
113
114           /**
115            * When called displays the indicator.
116            *
117            * @param indicator
118            */
119             function showRemaining(indicator) {
120                 indicator.css({
121                     display: 'block'
122                 });
123             }
124
125           /**
126            * When called shows the indicator.
127            *
128            * @param indicator
129            */
130             function hideRemaining(indicator) {
131                 indicator.css({
132                     display: 'none'
133                 });
134             }
135
136            /**
137            * This function updates the value in the indicator
138            *  
139            * @param maxLengthThisInput
140            * @param typedChars
141            * @return String
142            */
143             function updateMaxLengthHTML(maxLengthThisInput, typedChars) {
144                 var output = '';
145                 if (options.message){
146                     output = options.message.replace('%charsTyped%', typedChars)
147                             .replace('%charsRemaining%', maxLengthThisInput - typedChars)
148                             .replace('%charsTotal%', maxLengthThisInput);
149                 } else {
150                     if (options.preText) {
151                         output += options.preText;
152                     }
153                     if (!options.showCharsTyped) {
154                         output += maxLengthThisInput - typedChars;
155                     }
156                     else {
157                         output += typedChars;
158                     }
159                     if (options.showMaxLength) {
160                        output += options.separator + maxLengthThisInput;
161                     }
162                     if (options.postText) {
163                         output += options.postText;
164                     }
165                 }
166                 return output;
167             }
168
169           /**
170            * This function updates the value of the counter in the indicator.
171            * Wants as parameters: the number of remaining chars, the element currently managed,
172            * the maxLength for the current input and the indicator generated for it.
173            *
174            * @param remaining
175            * @param currentInput
176            * @param maxLengthCurrentInput
177            * @param maxLengthIndicator
178            */
179             function manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator) {
180                 maxLengthIndicator.html(updateMaxLengthHTML(maxLengthCurrentInput, (maxLengthCurrentInput - remaining)));
181
182                 if (remaining > 0) {
183                     if (charsLeftThreshold(currentInput, options.threshold, maxLengthCurrentInput)) {
184                         showRemaining(maxLengthIndicator.removeClass(options.limitReachedClass).addClass(options.warningClass));
185                     } else {
186                         hideRemaining(maxLengthIndicator);
187                     }
188                 } else {
189                     showRemaining(maxLengthIndicator.removeClass(options.warningClass).addClass(options.limitReachedClass));
190                 }
191             }
192
193           /**
194            * This function returns an object containing all the 
195            * informations about the position of the current input 
196            *  
197            *  @param currentInput
198            *  @return object {bottom height left right top  width}
199            *
200            */
201             function getPosition(currentInput) {
202                 var el = currentInput[0];
203                 return $.extend({}, (typeof el.getBoundingClientRect === 'function') ? el.getBoundingClientRect() : {
204                     width: el.offsetWidth,
205                     height: el.offsetHeight
206                 }, currentInput.offset());
207             }
208
209           /**
210            *  This function places the maxLengthIndicator at the
211            *  top / bottom / left / right of the currentInput
212            *
213            *  @param currentInput
214            *  @param maxLengthIndicator
215            *  @return null
216            *
217            */
218             function place(currentInput, maxLengthIndicator) {
219                 var pos = getPosition(currentInput),
220                     inputOuter = currentInput.outerWidth(),
221                     outerWidth = maxLengthIndicator.outerWidth(),
222                     actualWidth = maxLengthIndicator.width(),
223                     actualHeight = maxLengthIndicator.height();
224
225                 switch (options.placement) {
226                 case 'bottom':
227                     maxLengthIndicator.css({top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2});
228                     break;
229                 case 'top':
230                     maxLengthIndicator.css({top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2});
231                     break;
232                 case 'left':
233                     maxLengthIndicator.css({top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth});
234                     break;
235                 case 'right':
236                     maxLengthIndicator.css({top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width});
237                     break;
238                 case 'bottom-right':
239                     maxLengthIndicator.css({top: pos.top + pos.height, left: pos.left + pos.width});
240                     break;
241                 case 'top-right':
242                     maxLengthIndicator.css({top: pos.top - actualHeight, left: pos.left + inputOuter});
243                     break;
244                 case 'top-left':
245                     maxLengthIndicator.css({top: pos.top - actualHeight, left: pos.left - outerWidth});
246                     break;
247                 case 'bottom-left':
248                     maxLengthIndicator.css({top: pos.top + currentInput.outerHeight(), left: pos.left - outerWidth});
249                     break;
250                 case 'centered-right':
251                     maxLengthIndicator.css({top: pos.top + (actualHeight / 2), left: pos.left + inputOuter - outerWidth - 3});
252                     break;
253                 }
254             }
255
256             /**
257              *  This function retrieves the maximum length of currentInput
258              *
259              *  @param currentInput
260              *  @return {number}
261              *
262              */
263             function getMaxLength(currentInput) {
264                 return currentInput.attr('maxlength') || currentInput.attr('size');
265             }
266
267             return this.each(function() {
268
269                 var currentInput = $(this),
270                     maxLengthCurrentInput = getMaxLength(currentInput),
271                     maxLengthIndicator = $('<span></span>').css({
272                         display: 'none',
273                         position: 'absolute',
274                         whiteSpace: 'nowrap',
275                         zIndex: 1099
276                     }).html(updateMaxLengthHTML(maxLengthCurrentInput, '0'));
277
278                 // We need to detect resizes if we are dealing with a textarea:
279                 if (currentInput.is('textarea')) {
280                     currentInput.data('maxlenghtsizex', currentInput.outerWidth());
281                     currentInput.data('maxlenghtsizey', currentInput.outerHeight());
282
283                     currentInput.mouseup(function() {
284                         if (currentInput.outerWidth() !== currentInput.data('maxlenghtsizex') || currentInput.outerHeight() !== currentInput.data('maxlenghtsizey')) {
285                             place(currentInput, maxLengthIndicator);
286                         }
287
288                         currentInput.data('maxlenghtsizex', currentInput.outerWidth());
289                         currentInput.data('maxlenghtsizey', currentInput.outerHeight());
290                     });
291                 }
292
293                 documentBody.append(maxLengthIndicator);
294
295                 currentInput.focus(function() {
296                     var remaining = remainingChars(currentInput, getMaxLength(currentInput));
297                     manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator);
298                     place(currentInput, maxLengthIndicator);
299                 });
300
301                 $(window).resize(function() {
302                   place(currentInput, maxLengthIndicator);
303                 });
304
305                 currentInput.blur(function() {
306                     maxLengthIndicator.css('display', 'none');
307                 });
308
309                 currentInput.keyup(function(e) {
310                     var remaining = remainingChars(currentInput, getMaxLength(currentInput)),
311                         output = true,
312                         keyCode = e.keyCode || e.which;
313                     // Handle the tab press when the maxlength have been reached.
314                     if (remaining===0 && keyCode===9 && !e.shiftKey) {
315                       currentInput.attr('maxlength',getMaxLength(currentInput)+1)
316                                   .trigger({
317                                     type: 'keypress',
318                                     which: 9
319                                   }).attr('maxlength',getMaxLength(currentInput)-1);
320
321                     }
322                     if (options.validate && remaining < 0) {
323                         output = false;
324                     } else {
325                         manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator);
326                     }
327                     return output;
328                 });
329             });
330         }
331     });
332 }(jQuery));