I'm not very good at JavaScript, so it would be great if somebody could review my jQuery Upvote plugin, and point out mistakes, bad practices, or anything suspicious.
The repository is on GitHub. Here's a live demo, and qunit tests, if you're interested, but I'm not asking for a review of those.
Here's the code, with the header omitted (full version here):
;(function($) {
"use strict";
var namespace = 'upvote';
var dot_namespace = '.' + namespace;
var upvote_css = 'upvote';
var dot_upvote_css = '.' + upvote_css;
var upvoted_css = 'upvote-on';
var dot_upvoted_css = '.' + upvoted_css;
var downvote_css = 'downvote';
var dot_downvote_css = '.' + downvote_css;
var downvoted_css = 'downvote-on';
var dot_downvoted_css = '.' + downvoted_css;
var star_css = 'star';
var dot_star_css = '.' + star_css;
var starred_css = 'star-on';
var dot_starred_css = '.' + starred_css;
var count_css = 'count';
var dot_count_css = '.' + count_css;
var enabled_css = 'upvote-enabled';
function init(options) {
return this.each(function() {
methods.destroy.call(this);
var count = parseInt($(this).find(dot_count_css).text());
count = isNaN(count) ? 0 : count;
var initial = {
id: $(this).attr('data-id'),
count: count,
upvoted: $(this).find(dot_upvoted_css).size(),
downvoted: $(this).find(dot_downvoted_css).size(),
starred: $(this).find(dot_starred_css).size(),
callback: function() {}
};
var data = $.extend(initial, options);
if (data.upvoted && data.downvoted) {
data.downvoted = false;
}
var that = $(this);
that.data(namespace, data);
render(that);
setupUI(that);
});
}
function setupUI(that) {
that.find(dot_upvote_css).addClass(enabled_css);
that.find(dot_downvote_css).addClass(enabled_css);
that.find(dot_star_css).addClass(enabled_css);
that.find(dot_upvote_css).on('click.' + namespace, function() {
that.upvote('upvote');
});
that.find('.downvote').on('click.' + namespace, function() {
that.upvote('downvote');
});
that.find('.star').on('click.' + namespace, function() {
that.upvote('star');
});
}
function _click_upvote() {
this.find(dot_upvote_css).click();
}
function _click_downvote() {
this.find(dot_downvote_css).click();
}
function _click_star() {
this.find(dot_star_css).click();
}
function render(that) {
var data = that.data(namespace);
that.find(dot_count_css).text(data.count);
if (data.upvoted) {
that.find(dot_upvote_css).addClass(upvoted_css);
that.find(dot_downvote_css).removeClass(downvoted_css);
} else if (data.downvoted) {
that.find(dot_upvote_css).removeClass(upvoted_css);
that.find(dot_downvote_css).addClass(downvoted_css);
} else {
that.find(dot_upvote_css).removeClass(upvoted_css);
that.find(dot_downvote_css).removeClass(downvoted_css);
}
if (data.starred) {
that.find(dot_star_css).addClass(starred_css);
} else {
that.find(dot_star_css).removeClass(starred_css);
}
}
function callback(that) {
var data = that.data(namespace);
data.callback(data);
}
function upvote() {
var data = this.data(namespace);
if (data.upvoted) {
data.upvoted = false;
--data.count;
} else {
data.upvoted = true;
++data.count;
if (data.downvoted) {
data.downvoted = false;
++data.count;
}
}
render(this);
callback(this);
return this;
}
function downvote() {
var data = this.data(namespace);
if (data.downvoted) {
data.downvoted = false;
++data.count;
} else {
data.downvoted = true;
--data.count;
if (data.upvoted) {
data.upvoted = false;
--data.count;
}
}
render(this);
callback(this);
return this;
}
function star() {
var data = this.data(namespace);
data.starred = ! data.starred;
render(this);
callback(this);
return this;
}
function count() {
return this.data(namespace).count;
}
function upvoted() {
return this.data(namespace).upvoted;
}
function downvoted() {
return this.data(namespace).downvoted;
}
function starred() {
return this.data(namespace).starred;
}
var methods = {
init: init,
count: count,
upvote: upvote,
upvoted: upvoted,
downvote: downvote,
downvoted: downvoted,
starred: starred,
star: star,
_click_upvote: _click_upvote,
_click_downvote: _click_downvote,
_click_star: _click_star,
destroy: destroy
};
function destroy() {
return $(this).each(function() {
$(window).unbind(dot_namespace);
$(this).removeClass(enabled_css);
$(this).removeData(namespace);
});
}
$.fn.upvote = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
}
if (typeof method === 'object' || ! method) {
return methods.init.apply(this, arguments);
}
$.error('Method ' + method + ' does not exist on jQuery.upvote');
};
})(jQuery);
I pasted the code into jshint.com, and it gives 21 warnings: "Possible strict violation", for most but not all places where I use this
. What does that mean, and how to improve it?