/****************************************************************************************************** jQuery.NobleCount Author Jeremy Horn Version 1.0 Date: 3/21/2010 Copyright (c) 2010 Jeremy Horn- jeremydhorn(at)gmail(dot)c0m | http://tpgblog.com Dual licensed under MIT and GPL. DESCRIPTION NobleCount... for a more 'proper' count of the characters remaining. NobleCount is a customizable jQuery plugin for a more the improved counting of the remaining characters, and resulting behaviors, of a text entry object, e.g. input textfield, textarea. As text is entered into the target text area an object for the purposes of tracking the total number of characters remaining, defined as the maximum number of characters minus the current total number of characters within the text entry object, and storing that information visually and/or within the DOM as an HTML 5 compliant data-* attribute. Events and CSS Class alterations, if defined, are triggered based on current user interaction with the target text entry object as well as the current state (positive or negative) of the character remaining value. NobleCount supports pre-existing text within the text object. NobleCount supports jQuery chaining. Within NobleCount context... NEGATIVE is defined as Integers < 0 POSITIVE is defined as Integers >= 0 [on_positive will fire when char_rem == 0] BY DEFAULT - maximum characters EQUAL 140 characters - no events defined - no class changes defined - no DOM attributes are created/altered - user permitted to type past the maximum number of characters limit, resulting in negative number of characters remaining IMPLEMENTATION $('#textarea1').NobleCount('#characters_remaining1'); $('#textfield2').NobleCount('#characters_remaining2', { / * OPTIONS * / }); COMPATIBILITY Tested in FF3.5, IE7 With jQuery 1.3.x, 1.4.x METHOD(S) To properly intialize, both the text entry object and the object that will store the total number of characters remaining must exist and be passed to NobleCount. $(TEXT_ENTRY_OBJECT).NobleCount(CHARACTERS_REMAINING_OBJECT); Any callback functions assigned to any of the availale events are passed the following parameters: t_obj, char_area, c_settings, char_rem t_obj text entry object char_area selection of the characters remaining object c_settings result of the options passed into NobleCount at time of initialization merged with the default options ** this is a GREAT way to pass in and remember other state information that will be needed upon the triggering of NobleCount events ** char_rem integer representation of the total number of characters remaining resulting from the calculated difference between the target maximum number of characters and the current number of characters currently within t_obj Both TEXT_ENTRY_OBJECT and CHARACTERS_REMAINING_OBJECT must be specified and valid. Upon successful initialization, all appropriate events and classes are applied to the CHARACTERS_REMAINING_OBJECT, including the storage (if not disabled) visually or only in the DOM (if enabled) of the integer representing the number of characters remaining. The target maximum number of characters (max_chars) are determined by the following precedence rules.... if max_chars passed via constructor max_chars = max_chars passed else if number exists within characters_remaining object and number > 0 max_chars = number within the text() of characters_remaining object else use the NobleCount's default max_chars CUSTOMIZATION NobleCount(c_obj, ) e.g. $(t_obj).NobleCount(c_obj, {max_chars:100px}); on_negative class (STRING) or FUNCTION that is applied/called when characters remaining is negative IF DEFINED on_positive class (STRING) or FUNCTION that is applied/called when characters remaining is positive IF DEFINED on_update FUNCTION that is called when characters remaining changes max_chars target maximum number of characters block_negative if TRUE, then all attempts are made to block entering more than max_characters; not effective against user pasting in blocks of text that exceed the max_chars value otherwise, text area will let individual entering the text to exceed max_chars limit (characters remaining becomes negative) cloak: false, if TRUE, then no visual updates of characters remaining object (c_obj) will occur; this does not have any effect on the char_rem value returned via any event callbacks otherwise, the text within c_obj is constantly updated to represent the total number of characters remaining until the max_chars limit has been reached in_dom: false if TRUE and cloak is ALSO TRUE, then the number of characters remaining are stored as the attribute of c_obj named 'data-noblecount' !NOTE: if enabled, due to constant updating of a DOM element attribute user experience can appear sluggish while the individual is modifying the text entry object (t_obj) EXAMPLE OPTIONS = { on_negative: 'go_red', on_positive: 'go_green', max_chars: 25, on_update: function(t_obj, char_area, c_settings, char_rem){ if ((char_rem % 10) == 0) { char_area.css('font-weight', 'bold'); char_area.css('font-size', '300%'); } else { char_area.css('font-weight', 'normal'); char_area.css('font-size', '100%'); } } }; MORE For more details about NobleCount, its implementation, usage, and examples, go to: http://tpgblog.com/noblecount/ ******************************************************************************************************/ (function($) { /********************************************************************************** FUNCTION NobleCount DESCRIPTION NobleCount method constructor allows for customization of maximum length and related update/length behaviors e.g. $(text_obj).NobleCount(characters_remaining_obj); REQUIRED: c_obj OPTIONAL: options **********************************************************************************/ $.fn.NobleCount = function(c_obj, options) { var c_settings; var mc_passed = false; // if c_obj is not specified, then nothing to do here if (typeof c_obj == 'string') { // check for new & valid options c_settings = $.extend({}, $.fn.NobleCount.settings, options); // was max_chars passed via options parameter? if (typeof options != 'undefined') { mc_passed = ((typeof options.max_chars == 'number') ? true : false); } // process all provided objects return this.each(function(){ var $this = $(this); // attach events to c_obj attach_nobility($this, c_obj, c_settings, mc_passed); }); } return this; }; /********************************************************************************** FUNCTION NobleCount.settings DESCRIPTION publically accessible data stucture containing the max_chars and event handling specifications for NobleCount can be directly accessed by '$.fn.NobleCount.settings = ... ;' **********************************************************************************/ $.fn.NobleCount.settings = { on_negative: null, // class (STRING) or FUNCTION that is applied/called // when characters remaining is negative on_positive: null, // class (STRING) or FUNCTION that is applied/called // when characters remaining is positive on_update: null, // FUNCTION that is called when characters remaining // changes max_chars: 140, // maximum number of characters block_negative: false, // if true, then all attempts are made to block entering // more than max_characters cloak: false, // if true, then no visual updates of characters // remaining (c_obj) occur in_dom: false // if true and cloak == true, then number of characters // remaining are stored as the attribute // 'data-noblecount' of c_obj }; ////////////////////////////////////////////////////////////////////////////////// // private functions and settings /********************************************************************************** FUNCTION attach_nobility DESCRIPTION performs all initialization routines and display initiation assigns both the keyup and keydown events to the target text entry object; both keyup and keydown are used to provide the smoothest user experience if max_chars_passed via constructor max_chars = max_chars_passed else if number exists within counting_object (and number > 0) max_chars = counting_object.number else use default max_chars PRE t_obj and c_obj EXIST c_settings and mc_passed initialized POST maximum number of characters for t_obj calculated and stored in max_char key events attached to t_obj **********************************************************************************/ function attach_nobility(t_obj, c_obj, c_settings, mc_passed){ var max_char = c_settings.max_chars; var char_area = $(c_obj); // first determine if max_char needs adjustment if (!mc_passed) { var tmp_num = char_area.text(); var isPosNumber = (/^[1-9]\d*$/).test(tmp_num); if (isPosNumber) { max_char = tmp_num; } } // initialize display of characters remaining // * note: initializing should not trigger on_update event_internals(t_obj, char_area, c_settings, max_char, true); // then attach the events -- seem to work better than keypress $(t_obj).keydown(function(e) { event_internals(t_obj, char_area, c_settings, max_char, false); // to block text entry, return false if (check_block_negative(e, t_obj, c_settings, max_char) == false) { return false; } }); $(t_obj).keyup(function(e) { event_internals(t_obj, char_area, c_settings, max_char, false); // to block text entry, return false if (check_block_negative(e, t_obj, c_settings, max_char) == false) { return false; } }); } /********************************************************************************** FUNCTION check_block_negative DESCRIPTION determines whether or not text entry within t_obj should be prevented PRE e EXISTS t_obj VALID c_settings and max_char initialized / calculated POST if t_obj text entry should be prevented FALSE is returned otherwise TRUE returned TODO improve selection detection and permissible behaviors experience ALSO doesnt CURRENTLY block from the pasting of large chunks of text that exceed max_char **********************************************************************************/ function check_block_negative(e, t_obj, c_settings, max_char){ if (c_settings.block_negative) { var char_code = e.which; var selected; // goofy handling required to work in both IE and FF if (typeof document.selection != 'undefined') { selected = (document.selection.createRange().text.length > 0); } else { selected = (t_obj[0].selectionStart != t_obj[0].selectionEnd); } //return false if can't write more if ((!((find_remaining(t_obj, max_char) < 1) && (char_code > 47 || char_code == 32 || char_code == 0 || char_code == 13) && !e.ctrlKey && !e.altKey && !selected)) == false) { // block text entry return false; } } // allow text entry return true; } /********************************************************************************** FUNCTION find_remaining DESCRIPTION determines of the number of characters permitted (max_char), the number of characters remaining until that limit has been reached PRE t_obj and max_char EXIST and are VALID POST returns integer of the difference between max_char and total number of characters within the text entry object (t_obj) **********************************************************************************/ function find_remaining(t_obj, max_char){ return max_char - ($(t_obj).val()).length; } /********************************************************************************** FUNCTION event_internals DESCRIPTION primarily used for the calculation of appropriate behavior resulting from any event attached to the text entry object (t_obj) whenever the char_rem and related display and/or DOM information needs updating this function is called if cloaking is being used, then no visual representation of the characters remaining, nor attempt by this plugin to change any of its visual characteristics will occur if cloaking and in_dom are both TRUE, then the number of characters remaining are stored within the HTML 5 compliant attribute of the character count remaining object (c_obj) labeled 'data-noblecount' PRE c_settings, init_disp initialized POST performs all updates to the DOM visual and otherwise required performs all relevant function calls **********************************************************************************/ function event_internals(t_obj, char_area, c_settings, max_char, init_disp) { var char_rem = find_remaining(t_obj, max_char); // is chararacters remaining positive or negative if (char_rem < 0) { toggle_states(c_settings.on_negative, c_settings.on_positive, t_obj, char_area, c_settings, char_rem); } else { toggle_states(c_settings.on_positive, c_settings.on_negative, t_obj, char_area, c_settings, char_rem); } // determine whether or not to update the text of the char_area (or c_obj) if (c_settings.cloak) { // this slows stuff down quite a bit; TODO: implement better method of publically accessible data storage if (c_settings.in_dom) { char_area.attr('data-noblecount', char_rem); } } else { // show the numbers of characters remaining char_area.text(char_rem); } // if event_internals isn't being called for initialization purposes and // on_update is a properly defined function then call it on this update if (!init_disp && jQuery.isFunction(c_settings.on_update)) { c_settings.on_update(t_obj, char_area, c_settings, char_rem); } } /********************************************************************************** FUNCTION toggle_states DESCRIPTION performs the toggling operations between the watched positive and negative characteristics first, enables/triggers/executes the toggle_on behavior/class second, disables the trigger_off class PRE toggle_on, toggle_off IF DEFINED, must be a string representation of a VALID class OR must be a VALID function POST toggle_on objects have been applied/executed toggle_off class has been removed (if it is a class) **********************************************************************************/ function toggle_states(toggle_on, toggle_off, t_obj, char_area, c_settings, char_rem){ if (toggle_on != null) { if (typeof toggle_on == 'string') { char_area.addClass(toggle_on); } else if (jQuery.isFunction(toggle_on)) { toggle_on(t_obj, char_area, c_settings, char_rem); } } if (toggle_off != null) { if (typeof toggle_off == 'string') { char_area.removeClass(toggle_off); } } } })(jQuery);