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(' ');
} 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);
1 Answer 1
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(' ');
} 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);