Skip to content

Commit

Permalink
Merge pull request #31 from cstansbury/master
Browse files Browse the repository at this point in the history
Fixes/Enhancements/Code reduction
  • Loading branch information
javiertoledo committed May 25, 2015
2 parents 7920b4a + c3fdc11 commit 92cdc1d
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 138 deletions.
2 changes: 1 addition & 1 deletion build/bootstrap-rating-input.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"name": "bootstrap-rating-input",
"version": "0.2.5",
"version": "0.3.0",
"repository": "https://github.com/javiertoledo/bootstrap-rating-input.git",
"main": "src/bootstrap-rating-input.js",
"devDependencies": {
"uglify-js": "1.3.5",
"grunt": "0.4.2",
Expand Down
260 changes: 124 additions & 136 deletions src/bootstrap-rating-input.js
Original file line number Diff line number Diff line change
@@ -1,156 +1,144 @@
(function ($) {
(function($) {

$.fn.rating = function () {
var clearClass = 'rating-clear';
var clearSelector = '.' + clearClass;
var hiddenClass = 'hidden';

var element;
var starSelector = function(value) {
return '[data-value' + (value ? ('=' + value) : '') + ']';
};

// A private function to highlight a star corresponding to a given value
function _paintValue(ratingInput, value, active_icon, inactive_icon) {
var selectedStar = $(ratingInput).find('[data-value="' + value + '"]');
selectedStar.removeClass(inactive_icon).addClass(active_icon);
selectedStar.prevAll('[data-value]').removeClass(inactive_icon).addClass(active_icon);
selectedStar.nextAll('[data-value]').removeClass(active_icon).addClass(inactive_icon);
}
var toggleActive = function($el, active, options) {
var activeClass = options['active-icon'];
var inactiveClass = options['inactive-icon'];
$el.removeClass(active ? inactiveClass : activeClass).addClass(active ? activeClass : inactiveClass);
};

// A private function to remove the highlight for a selected rating
function _clearValue(ratingInput, active_icon, inactive_icon) {
var self = $(ratingInput);
self.find('[data-value]').removeClass(active_icon).addClass(inactive_icon);
var createRatingEl = function($input, options) {
var min = options.min;
var max = options.max;
var clearable = options.clearable;
var $ratingEl = $('<div class="rating-input"></div>');
for (var i = min; i <= max; i++) {
$ratingEl.append('<i class="' + options['icon-lib'] + '" data-value="' + i + '"></i>');
}

// A private function to change the actual value to the hidden field
function _updateValue(input, val) {
input.val(val).trigger('change');
if (val === input.data('empty-value')) {
input.siblings('.rating-clear').hide();
} else {
input.siblings('.rating-clear').show();
}
if (clearable) {
$ratingEl.append('&nbsp;').append(
'<a class="' + clearClass + '">' +
'<i class="' + options['icon-lib'] + ' ' + options['clearable-icon'] + '"/>' +
clearable +
'</a>'
);
}
return $ratingEl;
};

var inputOptions = function($input) {
var options = {};
for (option in DEFAULTS) {
options[option] = $input.data(option);
};
return options;
};

var DEFAULTS = {
'min': 1,
'max': 5,
'icon-lib': 'glyphicon',
'active-icon': 'glyphicon-star',
'inactive-icon': 'glyphicon-star-empty',
'clearable': '',
'clearable-icon': 'glyphicon-remove'
};

var Rating = function(input, options) {
var $input = this.$input = $(input);
var ratingOptions = this.options = $.extend({}, DEFAULTS, inputOptions($input), options);
var $ratingEl = this.$el = createRatingEl($input, ratingOptions);
$input.addClass(hiddenClass).before($ratingEl);
this.highlight(ratingOptions.value);
};

Rating.VERSION = '0.3.0';

// Iterate and transform all selected inputs
for (element = this.length - 1; element >= 0; element--) {

var el, i,
originalInput = $(this[element]),
max = originalInput.data('max') || 5,
min = originalInput.data('min') || 0,
def_val = originalInput.val() || 0,
lib = originalInput.data('icon-lib') || 'glyphicon'
active = originalInput.data('active-icon') || 'glyphicon-star',
inactive = originalInput.data('inactive-icon') || 'glyphicon-star-empty',
clearable = originalInput.data('clearable') || null,
clearable_i = originalInput.data('clearable-icon') || 'glyphicon-remove',
stars = '';

// HTML element construction
for (i = min; i <= max; i++) {
// Create <max> empty stars
if(i <= def_val){
stars += ['<i class="',lib, ' ', active, '" data-value="', i, '"></i>'].join('');
}
else{
stars += ['<i class="',lib, ' ', inactive, '" data-value="', i, '"></i>'].join('')
}
Rating.DEFAULTS = DEFAULTS;

Rating.prototype = {

clear: function() {
this.setValue(this.options.min - 1);
},

setValue: function(value) {
this.highlight(value);
this.updateInput(value);
},

highlight: function(value, skipClearable) {
var options = this.options;
var normValue = value - options.min + 1;
var $el = this.$el;
var $selected = $el.find(starSelector(normValue));
if (normValue) {
toggleActive($selected.prevAll('i').andSelf(), true, options);
toggleActive($selected.nextAll('i'), false, options);
} else {
toggleActive($selected, false, options);
}
// Add a clear link if clearable option is set
if (clearable) {
stars += [
' <a class="rating-clear" style="display:none;" href="javascript:void">',
'<span class="',lib,' ',clearable_i,'"></span> ',
clearable,
'</a>'].join('');
if (!skipClearable) {
$el.find(clearSelector).toggleClass(hiddenClass, !normValue);
}
},

// Clone with data and events the original input to preserve any additional data and event bindings.
var newInput = originalInput.clone(true)
.addClass('hidden')
.data('max', max)
.data('min', min)
.data('icon-lib', lib)
.data('active-icon', active)
.data('inactive-icon', inactive);

// Rating widget is wrapped inside a div
el = [
'<div class="rating-input">',
stars,
'</div>'].join('');

// Replace original inputs HTML with the new one
if (originalInput.parents('.rating-input').length <= 0) {
originalInput.replaceWith($(el).append(newInput));
updateInput: function(value) {
var normValue = value + this.options.min - 1;
var $input = this.$input;
if ($input.val() != normValue) {
$input.val(normValue).change();
}

}

// Give live to the newly generated widgets
$('.rating-input')
// Highlight stars on hovering
.on('mouseenter', '[data-value]', function () {
var self = $(this);
input = self.siblings('input');
_paintValue(self.closest('.rating-input'), self.data('value'), input.data('active-icon'), input.data('inactive-icon'));
})
// View current value while mouse is out
.on('mouseleave', '[data-value]', function () {
var self = $(this),
input = self.siblings('input'),
val = input.val(),
min = input.data('min'),
max = input.data('max'),
active = input.data('active-icon'),
inactive = input.data('inactive-icon');
if (val >= min && val <= max) {
_paintValue(self.closest('.rating-input'), val, active, inactive);
} else {
_clearValue(self.closest('.rating-input'), active, inactive);
}
})
// Set the selected value to the hidden field
.on('click', '[data-value]', function (e) {
var self = $(this),
val = self.data('value'),
input = self.siblings('input');
_updateValue(input,val);
e.preventDefault();
return false;
})
// Remove value on clear
.on('click', '.rating-clear', function (e) {
var self = $(this),
input = self.siblings('input'),
active = input.data('active-icon'),
inactive = input.data('inactive-icon');
_updateValue(input, input.data('empty-value'));
_clearValue(self.closest('.rating-input'), active, inactive);
e.preventDefault();
return false;
})
// Initialize view with default value
.each(function () {
var input = $(this).find('input'),
val = input.val(),
min = input.data('min'),
max = input.data('max');
if (val !== "" && +val >= min && +val <= max) {
_paintValue(this, val);
$(this).find('.rating-clear').show();
}
else {
input.val(input.data('empty-value'));
_clearValue(this);
}
});
};

var Plugin = $.fn.rating = function(option) {
return this.each(function() {
var $input = $(this);
var dataKey = 'rating';
var rating = $input.data(dataKey);
var options = typeof option === 'object' && option;

if (!rating) {
rating = new Rating($input, options);
rating.$el
.on('mouseenter', starSelector(), function () {
rating.highlight($(this).data('value'), true);
})
.on('mouseleave', starSelector(), function () {
rating.highlight($input.val(), true);
})
.on('click', starSelector(), function() {
rating.setValue($(this).data('value'));
})
.on('click', clearSelector, function() {
rating.clear();
});
$input.data(dataKey, rating);
}

if (option === 'clear') {
rating.clear();
} else if (option === 'setValue') {
rating.setValue(arguments[1]);
}
});
};

// Auto apply conversion of number fields with class 'rating' into rating-fields
Plugin.Constructor = Rating;

$(function () {
if ($('input.rating[type=number]').length > 0) {
$('input.rating[type=number]').rating();
}
$('input.rating[type=number]').each(function() {
$(this).rating();
});
});

}(jQuery));
}(jQuery));

0 comments on commit 92cdc1d

Please sign in to comment.