﻿/*
  @author: remy sharp / http://remysharp.com
  @params:
    feedback - the selector for the element that gives the user feedback. Note that this will be relative to the form the plugin is run against.
    hardLimit - whether to stop the user being able to keep adding characters. Defaults to true.
    useInput - whether to look for a hidden input named 'maxlength' instead of the maxlength attribute. Defaults to false.
    words - limit by characters or words, set this to true to limit by words. Defaults to false.
  @license: Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/
  @version: 1.2
  @changes: code tidy via Ariel Flesler and fix when pasting over limit and including \t or \n
*/

(function($) {

    $.fn.maxlength = function(settings) {

        if (typeof settings == 'string') {
            settings = { feedback: settings };
        }

        settings = $.extend({}, $.fn.maxlength.defaults, settings);

        function length(el) {
            var parts = el.value;
            if (settings.words)
                parts = el.value.length ? parts.split(/\s+/) : { length: 0 };
            return parts.length;
        }

        return this.each(function() {
            var field = this,
        	$field = $(field),
        	$form = $(field.form),
        	limit = settings.useInput ? $form.find('input[name=maxlength]').val() : $field.attr('maxlength'),
        	$charsLeft = $form.find(settings.feedback);
            
            function limitCheck(event) {
                var len = length(this),
        	    exceeded = len >= limit,
        		code = event.keyCode;

                if (!exceeded)
                    return;

                switch (code) {
                    case 8:  // allow delete
                    case 9:
                    case 17:
                    case 36: // and cursor keys
                    case 35:
                    case 37:
                    case 38:
                    case 39:
                    case 40:
                    case 46:
                    case 65:
                        return;

                    default:
                        return settings.words && code != 32 && code != 13 && len == limit;
                }
            }


            var updateCount = function() {
                var len = length(field),
            	diff = limit - len;

                $charsLeft.html(diff || "0");

                // truncation code
                if (settings.hardLimit && diff < 0) {
                    field.value = settings.words ?
                    // split by white space, capturing it in the result, then glue them back
            		field.value.split(/(\s+)/, (limit * 2) - 1).join('') :
            		field.value.substr(0, limit);

                    updateCount();
                }
            };

            $field.keyup(updateCount).change(updateCount);
            if (settings.hardLimit) {
                $field.keydown(limitCheck);
            }

            updateCount();
        });
    };

    $.fn.maxlength.defaults = {
        useInput: false,
        hardLimit: true,
        feedback: '.charsLeft',
        words: false
    };

})(jQuery);
