2
\$\begingroup\$

I wrote my first jQuery plugin. It counts characters in a similar way to what StackExchange uses for comment entries. You can see it in action with this fiddle.

I feel that it's messy, but I can't explain why. One of the default options is defined outside the defaults hash because it uses a self-reference, and the method for flashing the text seems out of place. I'm also a little worried about how it handles form submission, and its prevention when the minimum number of characters is not met.

I'm not very fluent with jQuery so I expect this to be atrocious. I would love to hear some feedback as to why, or how it could be improved.

The form is submitted via ajax, using Rails' unobtrusive JS.

(function ($) {
    "use strict";

    $.fn.counter = function (options) {
        var defaults = {
            minimumSize: 15,
            minimumWarning: " more to go...",
            maximumSize: 25,
            maximumWarning: " characters remaining...",
            warningSize: 20,
            targetClass: '.help-block'
        };

        defaults.defaultText = "Enter at least " + defaults.minimumSize + " characters.";    
        options = $.extend(defaults, options);

        function count(elem) {
            var size = elem.val().length, target = elem.siblings(options.targetClass);
            if (size === 0) {
                target.html(options.defaultText);
            } else if (size < options.minimumSize) {
                target.html((options.minimumSize - size) + options.minimumWarning);
            } else if (size >= options.minimumSize && size < options.warningSize) {
                target.html('&nbsp;');
            } else if (size >= options.warningSize && size < options.maximumSize) {
                target.html((options.maximumSize - size) + options.maximumWarning);
            } else if (size >= options.maximumSize) {
                elem.val(elem.val().substring(0, options.maximumSize));
                target.html("0" + options.maximumWarning);
            }
        }

        this.each(function () {
            var elem = $(this);
            count(elem);
            elem.keyup(function () {
                count(elem);
            });
            elem.closest('form').submit(function () {
                if (elem.val().length < options.minimumSize) {
                    $(this).find(options.targetClass).fadeOut('fast').fadeIn('fast').fadeOut('fast').fadeIn('fast');
                    return false;
                }
            });
            return elem;
        });
    };
})(jQuery);
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I suggest storing your defaults in a location that can be reached by the developers, and automatically filling in the minsize if minsize is included in the default text. For example,

(function ($) {
    "use strict";

    $.fn.counter = function (options) {
        options = $.extend($.fn.counter.defaults, options);

        function defaultText() {
            return options.defaultText.replace(/minsize/ig,options.minimumSize);
        }
        function count(elem) {
            var size = elem.val().length, target = elem.siblings(options.targetClass);
            if (size === 0) {
                target.html(defaultText());
            } else if (size < options.minimumSize) {
                target.html((options.minimumSize - size) + options.minimumWarning);
            } else if (size >= options.minimumSize && size < options.warningSize) {
                target.html('&nbsp;');
            } else if (size >= options.warningSize && size < options.maximumSize) {
                target.html((options.maximumSize - size) + options.maximumWarning);
            } else if (size >= options.maximumSize) {
                elem.val(elem.val().substring(0, options.maximumSize));
                target.html("0" + options.maximumWarning);
            }
        }

        this.each(function () {
            var elem = $(this);
            count(elem);
            elem.keyup(function () {
                count(elem);
            });
            elem.closest('form').submit(function () {
                if (elem.val().length < options.minimumSize) {
                    $(this).find(options.targetClass).fadeOut('fast').fadeIn('fast').fadeOut('fast').fadeIn('fast');
                    return false;
                }
            });
            return elem;
        });
    };

    $.fn.counter.defaults = {
        minimumSize: 15,
        minimumWarning: ' more to go...',
        maximumSize: 25,
        maximumWarning: ' characters remaining...',
        warningSize: 20,
        targetClass: '.help-block',
        defaultText: 'Enter at least minsize characters.'
    };
})(jQuery);
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.