(function ($) { var pluginName = "starRating"; var defaultOptions = { starCount: 5, readOnly: false, interval: 1, size: '30px' }; var methods = { initialize: function(opts) { return this.each(function() { var $input = $(this); var attrOpts = {}; var inputData = $input.data(); if (inputData[pluginName.toLowerCase()] === true) { if (console && console.log) { console.log("star rating has already been initialized; skipping..."); } return; } $input.attr("data-" + pluginName.toLowerCase(), "true"); if (inputData.interval) { attrOpts.interval = inputData.interval; } if (inputData.starcount) { attrOpts.starCount = inputData.starcount; } if (inputData.size) { attrOpts.size = inputData.size; } if ($input.is(":disabled")) { attrOpts.readOnly = true; } var options = _.extend({}, defaultOptions, attrOpts, opts); var $widget = $("").addClass("star-rating").css({'font-size': options.size}); var $emptySet = $("").addClass("empty-set").appendTo($widget); var $filledSet = $("").addClass("filled-set").appendTo($widget); options.$input = $input; options.$emptySet = $emptySet; for (var x = 1; x <= options.starCount; x++) { $emptySet.append( $("").addClass("star empty") ); $filledSet.append( $("").addClass("star full") ); } $widget.data(pluginName + ".options", options); $input.data(pluginName, true).hide().after($widget); privateMethods.updateStars($widget); if (!options.readOnly) { $widget .on("click." + pluginName, function(e) { var value = privateMethods.calculateRating($widget, e.pageX); privateMethods.setValue($widget, value); }) .on("mousemove." + pluginName, function(e) { var value = privateMethods.calculateRating($widget, e.pageX); privateMethods.updateStars($widget, value); }) .on("mouseleave." + pluginName, function (e) { privateMethods.updateStars($widget); }); } $input .on("change." + pluginName, function() { privateMethods.updateStars($widget); }); }); } }; var privateMethods = { updateStars: function($widget, value) { var options = $widget.data(pluginName + ".options"); value = (value == null ? (parseFloat(options.$input.val() || 0)) : value); $widget.find(".filled-set").css({width: privateMethods.calculateWidth($widget, value)}); }, setValue: function($widget, value) { var options = $widget.data(pluginName + ".options"); options.$input.val(value); privateMethods.updateStars($widget); }, calculateWidth: function($widget, value) { var options = $widget.data(pluginName + ".options"); var width = options.$emptySet.width(); return ((value / options.starCount) * 100).toString() + "%"; }, // Given a screen X coordinate, calculates the nearest valid value for this rating widget calculateRating: function($widget, screenX) { var options = $widget.data(pluginName + ".options"); var offset = options.$emptySet.offset(); var width = options.$emptySet.width(); var ratio = (screenX - offset.left) / width; ratio = Math.max(0, Math.min(1, ratio)); return Math.ceil(options.starCount * (1 / options.interval) * ratio) / (1 / options.interval); } }; $.fn[pluginName] = function(method) { if (methods[method]) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === 'object' || ! method) { return methods.initialize.apply(this, arguments); } else { $.error('Method ' + method + ' does not exist on jQuery.' + pluginName); } }; })(jQuery);