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

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.