Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 191 additions & 69 deletions angular-input-stars.js
Original file line number Diff line number Diff line change
@@ -1,105 +1,227 @@
'use strict';

var __indexOf = [].indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (i in this && this[i] === item) return i;
}
return -1;
};

angular.module('angular-input-stars', [])
.service('FontAwesomeIcons', ['$http', '$q',
function($http, $q){

var iconData = {};
this.get = function(){

var deferred = $q.defer();

//Fetch icon list from font-awesome repo
$http.get('https://raw.githubusercontent.com/FortAwesome/Font-Awesome/gh-pages/icons.yml').then(function (response) {
var parsedData = jsyaml.load(response.data);

var parsedIconData = {
iconMap: {},
iconList: [],
iconCategoryList: []
};

var icons = parsedData.icons;

for (var i = 0; i < icons.length; i++) {
parsedIconData.iconMap[icons[i].name] = icons[i].id;
parsedIconData.iconList.push(icons[i].name);

for (var x = 0; x < icons[i].categories.length; x++) {
if (!parsedIconData.iconCategoryList[icons[i].categories[x]]) parsedIconData.iconCategoryList[icons[i].categories[x]] = [];
parsedIconData.iconCategoryList[icons[i].categories[x]].push(icons[i].name);
}
}

deferred.resolve(parsedIconData);
},
//Error Callback Function
function(data){
var error = response.data || "Request failed";
deferred.reject(error);
});

return deferred.promise;
}

}
]).filter('toFaIcon', ['FontAwesomeIcons', '$timeout',
function(FontAwesomeIcons, $timeout) {

var getRatingShape = function (fieldType, iconData) {
var iconObj = {
full: "",
empty: ""
};
console.log(fieldType);

if (__indexOf.call(iconData.iconList, fieldType) >= 0) {

iconObj.full = "fa-"+iconData.iconMap[fieldType];
iconObj.empty = "fa-"+iconData.iconMap[fieldType]+"-o";
if(fieldType == "thumbs-up" || fieldType == "thumbs-down"){
iconObj.empty = "fa-"+iconData.iconMap[fieldType].split("-")[0]+"-o-"+iconData.iconMap[fieldType].split("-")[1];
}else if(fieldType == "Smile Outlined"){
iconObj.empty = "fa-frown-o";
}

return iconObj;
} else {
console.error("Error no shape of type: " + fieldType + " for rating input");
return iconObj;
}
};


return function filterLogic(shapeType, isEmpty, faData) {
var shapeData = getRatingShape(shapeType, faData);

if(isEmpty) return shapeData.empty;
else return shapeData.full;
}

}
]).directive('inputStars', ['$rootScope', '$filter', 'FontAwesomeIcons', '$q',
function ($rootScope, $filter, FontAwesomeIcons, $q) {

console.log('hello');
var directive = {

restrict: 'EA',
replace: true,
template: '<ul ng-class="listClass">' +
'<li ng-touch="paintStars($index)" ng-mouseenter="paintStars($index, true)" ng-mouseleave="unpaintStars($index, false)" ng-repeat="item in items track by $index">' +
'<i ng-class="getClass($index)" ng-click="setValue($index, $event)"></i>' +
'</li>' +
'</ul>',
require: 'ngModel',
scope: true,

link: link

};

return directive;

.directive('inputStars', function () {
function link(scope, element, attrs, ngModelCtrl) {
console.log(attrs);
var obj = {};

var directive = {
(function initDirective() {
var deferred = $q.defer();
FontAwesomeIcons.get().then(function(result) {
deferred.resolve(result);
}, function (err) {
deferred.reject(new Error("toShapeIcon Error: " + err.message || err));
});

restrict: 'EA',
replace: true,
template: '<ul ng-class="listClass">' +
'<li ng-touch="paintStars($index)" ng-mouseenter="paintStars($index, true)" ng-mouseleave="unpaintStars($index, false)" ng-repeat="item in items track by $index">' +
'<i ng-class="getClass($index)" ng-click="setValue($index, $event)"></i>' +
'</li>' +
'</ul>',
require: 'ngModel',
scope: true,
return deferred.promise;
})().then(function (faData) {

link: link
//Initialize directive with font-awesome class names
(function initDirective(){
scope.items = new Array(+attrs.max);

};
obj.emptyIcon = $filter('toFaIcon')(attrs.iconEmpty, true, faData) || attrs.iconEmpty || 'fa-stars-o';
obj.iconHover = attrs.iconHover || 'angular-input-stars-hover';
obj.fullIcon = $filter('toFaIcon')(attrs.iconFull, false, faData) || attrs.iconEmpty || 'fa-stars';
obj.iconBase = attrs.iconBase || 'fa fa-fw';

return directive;
scope.listClass = attrs.listClass || 'angular-input-stars';
scope.readonly = !(attrs.readonly === undefined);
})();

function link(scope, element, attrs, ngModelCtrl) {
//Update directive when attributes are changed
attrs.$observe('max', function(max){
scope.items = new Array(+max);
});
attrs.$observe('iconEmpty', function(newEmptyIcon){
obj.emptyIcon = $filter('toFaIcon')(newEmptyIcon, true, faData) || newEmptyIcon || 'fa-stars-o';
});
attrs.$observe('iconFull', function(newFullIcon){
obj.fullIcon = $filter('toFaIcon')(newFullIcon, false, faData) || newFullIcon || 'fa-stars';
});

scope.items = new Array(+attrs.max);

var emptyIcon = attrs.iconEmpty || 'fa-star-o';
var iconHover = attrs.iconHover || 'angular-input-stars-hover';
var fullIcon = attrs.iconFull || 'fa-star';
var iconBase = attrs.iconBase || 'fa fa-fw';
scope.listClass = attrs.listClass || 'angular-input-stars';
scope.readonly = ! (attrs.readonly === undefined);
ngModelCtrl.$render = function () {

ngModelCtrl.$render = function () {
scope.last_value = ngModelCtrl.$viewValue || 0;

scope.last_value = ngModelCtrl.$viewValue || 0;
};

};
scope.getClass = function (index) {

scope.getClass = function (index) {
return index >= scope.last_value ? obj.iconBase + ' ' + obj.emptyIcon : obj.iconBase + ' ' + obj.fullIcon + ' active ';

return index >= scope.last_value ? iconBase + ' ' + emptyIcon : iconBase + ' ' + fullIcon + ' active ';
};

};
scope.unpaintStars = function ($index, hover) {

scope.unpaintStars = function ($index, hover) {
scope.paintStars(scope.last_value - 1, hover);

scope.paintStars(scope.last_value - 1, hover);
};

};
scope.paintStars = function ($index, hover) {

scope.paintStars = function ($index, hover) {
//ignore painting, if readonly
if (scope.readonly) {
return;
}
var items = element.find('li').find('i');

//ignore painting, if readonly
if (scope.readonly) {
return;
}
var items = element.find('li').find('i');
for (var index = 0; index < items.length; index++) {

for (var index = 0; index < items.length; index++) {
var $star = angular.element(items[index]);

var $star = angular.element(items[index]);
if ($index >= index) {

if ($index >= index) {

$star.removeClass(emptyIcon);
$star.addClass(fullIcon);
$star.addClass('active');
$star.addClass(iconHover);
$star.removeClass(obj.emptyIcon);
$star.addClass(obj.fullIcon);
$star.addClass('active');
$star.addClass(obj.iconHover);

} else {
} else {

$star.removeClass(fullIcon);
$star.removeClass('active');
$star.removeClass(iconHover);
$star.addClass(emptyIcon);
$star.removeClass(obj.fullIcon);
$star.removeClass('active');
$star.removeClass(obj.iconHover);
$star.addClass(obj.emptyIcon);

}
}
}
}

!hover && items.removeClass(iconHover);
!hover && items.removeClass(obj.iconHover);

};
};

scope.setValue = function (index, e) {
scope.setValue = function (index, e) {

//ignore painting
if (scope.readonly) {
return;
}
var star = e.target;
//ignore painting
if (scope.readonly) {
return;
}
var star = e.target;

if (e.pageX < star.getBoundingClientRect().left + star.offsetWidth / 2) {
scope.last_value = index + 1;
} else {
scope.last_value = index + 1;
}
if (e.pageX < star.getBoundingClientRect().left + star.offsetWidth / 2) {
scope.last_value = index + 1;
} else {
scope.last_value = index + 1;
}

ngModelCtrl.$setViewValue(scope.last_value);
ngModelCtrl.$setViewValue(scope.last_value);

};
//Execute custom trigger function if there is one
if (attrs.onShapeClick) {
scope.$eval(attrs.onStarClick);
}

}
};

});
});
}
}]);
1 change: 1 addition & 0 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"angular-input-stars.js"
],
"dependencies": {
"js-yaml": "~3.6.1",
"angular": "1.4.x",
"font-awesome": "~4.4.0"
},
Expand Down
23 changes: 23 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "angular-input-stars",
"version": "1.5.5",
"description": "AngularJS directive for rating inputs",
"private": false,
"homepage": "https://github.com/rcbytes/angular-input-stars",
"keywords": [
"angularjs",
"directive",
"input",
"stars",
"rating"
],
"author": {
"name": "Rafael Mello Campanari <lab.rafamello@gmail.com> (http://rafamello.com)"
},
"license": "MIT",
"main": "angular-input-stars.js",
"dependencies": {
"angular": "1.4.x",
"font-awesome": "~4.2.0"
}
}
7 changes: 6 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ You can customize the **base**, **empty**, **hover**, and **full** and icon cla
```
> Unlike icon-base, on icon-full, icon-hover and icon-empty you must specify only one class, but that is all you need : ]

You can add a $rootScope function that will be called each time after a star is clicked by using the optional **onStarClick** attribute
```html
<input-stars max="5" on-star-click="runMyFunction()" ng-model="YourCtrl.property"></input-stars>
```

You can customize the **list class** to whatever you want
```html
<input-stars max="5" list-class="shiny-list" ng-model="YourCtrl.property"></input-stars>
Expand All @@ -46,4 +51,4 @@ This directive uses [FontAwesome](http://fortawesome.github.io/Font-Awesome/) as

## License

MIT License © Rafael Mello Campanari
MIT License © Rafael Mello Campanari