Skip to content

Instantly share code, notes, and snippets.

@klarstil
Last active September 11, 2018 16:11
Show Gist options
  • Save klarstil/5642487 to your computer and use it in GitHub Desktop.
Save klarstil/5642487 to your computer and use it in GitHub Desktop.
Simple star rating
;(function ( $, window, document, undefined ) {
"use strict";
var pluginName = 'starRating', _lastActive = -1,
defaults = {
baseCls: 'star-rating',
activeCls: 'is-active',
hoverCls: 'is-hover',
nonInteractiveCls: 'is-non-interactive'
};
/**
* Plugin constructor which merges the default settings
* with the user configuration and sets up the DOM bridge.
*
* @param { HTMLElement } element
* @param { Object } options
* @returms { Void }
* @constructor
*/
function Plugin( element, options ) {
this.element = element;
this.$el = $(element);
this.options = $.extend( {}, defaults, options);
this._isInteractive = this.$el.attr('data-interactive');
this._defaults = defaults;
this._name = pluginName;
this.init();
}
/**
* Initialized the plugin, sets up the template
* and marks the selected as active.
*
* @returns { Void }
*/
Plugin.prototype.init = function () {
var me = this,
selected = me.$el.find(':selected');
me.$tpl = me.createTemplate();
if(me._isInteractive) {
me.bindEvents();
} else {
me.$tpl.addClass(me.options.nonInteractiveCls);
}
me.$el.replaceWith(me.$tpl);
if(selected && selected.val()) {
if(me._isInteractive) {
me.$tpl.find('a:nth-child(' + selected.val() + ')').trigger('click.' + pluginName);
} else {
me.onSetActive(selected.val());
}
}
};
/**
* Binds the event handlers to the elements.
*
* @returns { Void }
*/
Plugin.prototype.bindEvents = function() {
var me = this;
me.$tpl.delegate('a', 'click.' + pluginName, function(event) {
event.preventDefault();
_lastActive = ~~(1 * $(this).attr('data-star-rating-value'))
me.onSetActive(_lastActive);
});
me.$tpl.on('hover', function() {
me.$tpl.toggleClass(me.options.hoverCls);
});
me.$tpl.delegate('a', 'mouseenter.' + pluginName, function(event) {
event.preventDefault();
me.onSetActive(~~(1 * $(this).attr('data-star-rating-value')));
});
me.$tpl.on('mouseleave.' + pluginName, function(event) {
event.preventDefault();
if(_lastActive > 0) {
me.onSetActive(_lastActive);
} else {
me.onClearSelection(event)
}
});
};
/**
* Event listener which sets the incoming position active.
*
* @event click.starRating
* @param { Integer } pos
* @returns { Boolean }
*/
Plugin.prototype.onSetActive = function(pos) {
var me = this,
tpl = me.$tpl,
elements = tpl.find('a').removeClass(me.options.activeCls),
i = 0;
for(; i < pos; i++) {
$(elements[i]).addClass(me.options.activeCls);
}
return true;
};
/**
* Event listener which clears any selection
*
* @param {jQuery.Event } event
* @returns { Boolean }
*/
Plugin.prototype.onClearSelection = function(event) {
event.preventDefault();
var me = this,
tpl = me.$tpl;
tpl.find('a').removeClass(me.options.activeCls);
_lastActive = -1;
return true;
};
/**
* Creates the template for the plugin.
*
* @returns { jQuery }
*/
Plugin.prototype.createTemplate = function() {
var me = this,
options = me.$el.find('option'),
len = options.length, i = 0, option, clearEl, val,
container = $('<div>', { 'class': me.options.baseCls + '-container' });
for(; i < len; i++) {
option = $(options[i]);
val = option.val()
$('<a>', {
'class': me.options.baseCls + '-option ' + me.options.baseCls + '-option-' + val,
'href': '#rate-' + val,
'data-star-rating-value': val
}).appendTo(container);
}
if(me._isInteractive) {
$('<span>', { 'class': me.options.baseCls + '-clear' })
.appendTo(container)
.on('click', $.proxy(me.onClearSelection, me));
}
return container;
};
/** Lightweight plugin starter */
$.fn[pluginName] = function ( options ) {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new Plugin( this, options ));
}
});
}
$(function() {
$('[data-plugin=star-rating]').starRating();
});
})( jQuery, window, document );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment