diff options
Diffstat (limited to 'jquery.countable.js')
-rw-r--r-- | jquery.countable.js | 163 |
1 files changed, 94 insertions, 69 deletions
diff --git a/jquery.countable.js b/jquery.countable.js index b3e90ff..9f9af2b 100644 --- a/jquery.countable.js +++ b/jquery.countable.js @@ -1,6 +1,7 @@ -/*! Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net) - * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) - * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. +/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net) + * Licensed under the MIT License (LICENSE.txt). + * + * Version 1.0 * * Contributions by: * - Neil Monroe (neil.monroe[at]gmail.com) @@ -9,72 +10,96 @@ (function($) { $.fn.extend({ - countable: function(options) { - return this.each(function() { - var $this = $(this), interval, prev_char_diff, $el; - options = $.extend({ - threshold: .5, - appendMethod: 'insertAfter', // insertBefore || insertAfter || prependTo || appendTo - target: $this, // element in which to place the counter - startOpacity: .25, - maxLength: parseInt( $this.attr('maxlength'), 10 ) || 0, - maxClassName: 'maxed', - className: 'counter', - tagName: 'span', - interval: 750, - positiveCopy: 'You have {n} characters left.', - negativeCopy: 'You are {n} characters over.', - fadeDuration: 'normal', - defaultText: '' // text to disregard in the character count - }, options); - - $el = $('<'+options.tagName+'/>') - .html( options.positiveCopy.replace('{n}', '<span class="num"/>') ) - .addClass( options.className ); - if ( $.support.opacity ) $el.css({ opacity: 0 }); // don't set opacity for IE to avoid clear text issues. - $el[options.appendMethod](options.target); - - $this - .bind('keyup', check) - .bind('focus blur', function(event) { - if ( event.type == 'blur' ) clearInterval( interval ); - if ( event.type == 'focus' && !interval ) setInterval(check, options.interval); - }); - - function check() { - var val = $this.val(), length = (val == options.defaultText ? 0 : val.length), percentage_complete = length/options.maxLength, char_diff = options.maxLength - length; - if ( prev_char_diff != undefined && char_diff == prev_char_diff ) return; - opacity = options.startOpacity + ((options.threshold - percentage_complete) * ((options.startOpacity * 2) - 2)); - - if ( $el.is(':hidden') && percentage_complete >= options.threshold ) - $el.show(); - if ( $el.is(':visible') && percentage_complete < options.threshold ) - $el.hide(); - - if ( $.support.opacity ) // don't set opacity for IE to avoid clear text issues. - $el.stop().fadeTo( options.fadeDuration, percentage_complete >= options.threshold ? opacity : 0 ); - - if ( char_diff >= 0 ) { - if ( $el.is( '.'+options.maxClassName ) ) - $el.html( options.positiveCopy.replace('{n}', '<span class="num"/>') ); - } else { - if ( !$el.is( '.'+options.maxClassName ) ) - $el.html( options.negativeCopy.replace('{n}', '<span class="num"/>') ); - } - - $el[ (char_diff < 0 ? 'add' : 'remove') + 'Class' ]( options.maxClassName ); - $el.find('.num').text( Math.abs(char_diff) ); - - if ( char_diff == -1 || char_diff == 1 ) - $el.html( $el.html().replace(/characters\b/, 'character') ); - else - $el.html( $el.html().replace(/character\b/, 'characters') ); - - prev_char_diff = char_diff; - }; - check(); - }); - } + countable: function(givenOptions) { + return this.each(function() { + var $this = $(this), interval, prev_char_diff, $el, + options = $.extend({ + threshold: .5, + appendMethod: 'insertAfter', // insertBefore || insertAfter || prependTo || appendTo + target: $this, // relative element with which to place the counter + startOpacity: .25, + maxLength: parseInt( $this.attr('maxlength'), 10 ) || 0, + maxClassName: 'maxed', + className: 'counter', + tagName: 'span', + interval: 750, + positiveCopy: 'You have {n} characters left.', + negativeCopy: 'You are {n} characters over.', + fadeDuration: 'normal', + defaultText: '' // text to disregard in the character count + }, givenOptions); + + // create counter element + $el = $('<'+options.tagName+'/>') + .html( options.positiveCopy.replace('{n}', '<span class="num"></span>') ) + .addClass( options.className ); + + // set initial opacity to 0 if opacity is supported + if ( $.support.opacity ) $el.css({ opacity: 0 }); // don't set opacity for IE to avoid clear text issues. + + // sppend counter element to the DOM + $el[options.appendMethod](options.target); + + // hook up events for the input/textarea being monitored + $this + .bind('keyup', check) + .bind('focus blur', function(event) { + if ( event.type == 'blur' ) clearInterval( interval ); + if ( event.type == 'focus' && !interval ) setInterval(check, options.interval); + }); + + // actual function to do the character counting and notification + function check() { + var val = $this.val(), + length = (val == options.defaultText ? 0 : val.length), + percentage_complete = length/options.maxLength, + char_diff = options.maxLength - length, + opacity; + + // return if we haven't made any progress + if ( prev_char_diff != undefined && char_diff == prev_char_diff ) return; + + // if counter element is hidden and we are past the given threshold, show it + if ( $el.is(':hidden') && percentage_complete >= options.threshold ) + $el.show(); + // if the counter element is visible and we are now under the given threshold, hide it + if ( $el.is(':visible') && percentage_complete < options.threshold ) + $el.hide(); + + if ( $.support.opacity ) { // don't set opacity for IE to avoid clear type issues. + // calculate the correct opacity + opacity = options.startOpacity + ((options.threshold - percentage_complete) * ((options.startOpacity * 2) - 2)); + // animate to the correct opacity + $el.stop().fadeTo( options.fadeDuration, percentage_complete >= options.threshold ? opacity : 0 ); + } + + // set the correct copy if under or over the max number of characters + if ( char_diff >= 0 ) { + if ( $el.is( '.'+options.maxClassName ) ) + $el.html( options.positiveCopy.replace('{n}', '<span class="num"></span>') ); + } else { + if ( !$el.is( '.'+options.maxClassName ) ) + $el.html( options.negativeCopy.replace('{n}', '<span class="num"></span>') ); + } + + // add or remove the max class name + $el[ (char_diff < 0 ? 'add' : 'remove') + 'Class' ]( options.maxClassName ); + + // set the number of characters left or number of characters over the limit + $el.find('.num').text( Math.abs(char_diff) ); + + // make sure the plural is necessary or not + if ( char_diff == -1 || char_diff == 1 ) + $el.html( $el.html().replace(/characters\b/, 'character') ); + else + $el.html( $el.html().replace(/character\b/, 'characters') ); + + prev_char_diff = char_diff; + }; + // run an initial check + check(); + }); + } }); })(jQuery);
\ No newline at end of file |