├── .gitignore ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── dist ├── ng-rateit.css ├── ng-rateit.js └── ng-rateit.min.js ├── example ├── bg-car.svg ├── cancel-icon.svg ├── custom.png ├── custom.psd ├── example.js ├── hover-car.svg ├── index.html ├── ng-rate-it.html └── rated-car.svg ├── ng-rate-it.png ├── package.json └── src ├── images ├── bg-star.svg ├── cancel-icon.svg ├── hover-star.svg └── rated-star.svg ├── ng-rateit.js ├── star.psd └── style └── ng-rateit.css /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /bower_components -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | 3 | module.exports = function (grunt) { 4 | 'use strict'; 5 | 6 | // Load grunt tasks automatically 7 | require('load-grunt-tasks')(grunt); 8 | 9 | // Define the configuration for all the tasks 10 | grunt.initConfig({ 11 | 12 | // Project settings 13 | config: { 14 | src: 'src', 15 | dist: 'dist', 16 | gh: 'gh-pages', 17 | tmp: '.tmp' 18 | }, 19 | 20 | // Empties folders to start fresh 21 | clean: { 22 | dist: { 23 | files: [{ 24 | dot: true, 25 | src: [ 26 | '.tmp', 27 | '<%= config.dist %>/**/*' 28 | ] 29 | }] 30 | }, 31 | gh: { 32 | files: [{ 33 | dot: true, 34 | src: [ 35 | '<%= config.gh %>' 36 | ] 37 | }] 38 | } 39 | }, 40 | 41 | // A multi-task to validate your JavaScript files with JSLint. 42 | jslint: { 43 | scripts: { 44 | src: ['<%= config.src %>/ng-rateit.js'], 45 | directives: { 46 | predef: ['angular','document','window','console'], 47 | white: true, 48 | regexp: true, 49 | newcap: true, 50 | todo: true 51 | } 52 | } 53 | }, 54 | 55 | removelogging: { 56 | dist: { 57 | src: "<%= config.src %>/ng-rateit.js", 58 | dest: "<%= config.dist %>/ng-rateit.js" 59 | } 60 | }, 61 | 62 | // ng-annotate tries to make the code safe for minification automatically 63 | // by using the Angular long form for dependency injection. 64 | ngAnnotate: { 65 | dist: { 66 | files: [{ 67 | expand: true, 68 | src: '<%= config.dist %>/ng-rateit.js', 69 | dest: '' 70 | }] 71 | } 72 | }, 73 | 74 | // Minify files with UglifyJS. 75 | uglify: { 76 | build: { 77 | files: { 78 | '<%= config.dist %>/ng-rateit.min.js': ['<%= config.dist %>/ng-rateit.js'] 79 | } 80 | } 81 | }, 82 | 83 | // This task converts all data found within a stylesheet (those within a url( ... ) declaration) 84 | // into base64-encoded data URI strings. This includes images and fonts. 85 | imageEmbed: { 86 | dist: { 87 | src: [ "<%= config.src %>/style/ng-rateit.css" ], 88 | dest: "<%= config.dist %>/ng-rateit.css", 89 | options: { 90 | deleteAfterEncoding : false 91 | } 92 | } 93 | }, 94 | 95 | // The following *-min tasks will produce minified files in the dist folder 96 | // By default, your `index.html`'s will take care of 97 | // minification. These next options are pre-configured if you do not wish 98 | // to use the Usemin blocks. 99 | cssmin: { 100 | dist: { 101 | files: { 102 | '<%= config.dist %>/ng-rateit.css': [ 103 | '<%= config.dist %>/ng-rateit.css' 104 | ] 105 | } 106 | } 107 | }, 108 | 109 | copy:{ 110 | gh:{ 111 | files: [ 112 | { 113 | cwd: 'example', 114 | src: '**/*', 115 | dest: '<%= config.gh %>', 116 | expand: true 117 | }, 118 | { 119 | src: ['dist/**/*'], 120 | dest: '<%= config.gh %>/' 121 | } 122 | ] 123 | } 124 | }, 125 | 126 | replace: { 127 | gh: { 128 | options: { 129 | usePrefix:false, 130 | patterns: [ 131 | { 132 | match: '../', 133 | replacement: '' 134 | } 135 | ] 136 | }, 137 | files: [ 138 | {src: ['<%= config.gh %>/index.html'], dest: '<%= config.gh %>/index.html'} 139 | ] 140 | } 141 | }, 142 | 143 | 'gh-pages': { 144 | options: { 145 | base: 'gh-pages', 146 | message: 'Auto-generated commit' 147 | }, 148 | src: ['**'] 149 | }, 150 | 151 | version: { 152 | project: { 153 | src: ['package.json', 'bower.json'] 154 | } 155 | } 156 | 157 | }); 158 | 159 | grunt.registerTask('build', [ 160 | 'clean:dist', 161 | 'jslint', 162 | 'removelogging', 163 | 'ngAnnotate', 164 | 'uglify', 165 | 'imageEmbed', 166 | 'cssmin' 167 | ]); 168 | 169 | grunt.registerTask('deploy-patch', [ 170 | 'version::patch', 171 | 'ghpage' 172 | ]); 173 | 174 | grunt.registerTask('ghpage', [ 175 | 'build', 176 | 'clean:gh', 177 | 'copy:gh', 178 | 'replace:gh', 179 | 'gh-pages', 180 | 'clean:gh', 181 | ]); 182 | 183 | }; 184 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Arjan Kempes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-rateit 2 | 3 | This directive was inspired by the jQuery (star)rating plugin [RateIt](http://rateit.codeplex.com/). 4 | However this package will work without jQuery and is very light weight. 5 | 6 | ![ng-rate-it](ng-rate-it.png?raw=true) 7 | 8 | [Live demo](http://akempes.github.io/angular-rateit/) 9 | 10 | ## Getting Started 11 | 12 | You can install an angular-rateit package easily using Bower: 13 | 14 | ```shell 15 | bower install angular-rateit 16 | ``` 17 | 18 | And add the files to your index page: 19 | 20 | ```html 21 | 22 | 23 | ``` 24 | 25 | Finally add 'ngRateIt' to your main module's list of dependencies: 26 | 27 | ```js 28 | angular.module('myApp', [ 29 | ... 30 | 'ngRateIt', 31 | ... 32 | ]); 33 | ``` 34 | 35 | ## How to use 36 | 37 | To get it working simply add this block of code to your view: 38 | 39 | ```html 40 | 41 | ``` 42 | **N.B.** When using angular 1.2.* use `
` 43 | 44 | For more advanced functionality you can add a couple attributes: 45 | 46 | ```html 47 | 62 | 63 | ``` 64 | 65 | ### Attributes 66 | 67 | | Attribute | Description | Value | Default | 68 | |---|---|---|---| 69 | | ng-model | Object bound to control. (Required) | String, Number, Array | - | 70 | | min | Minimal value. | Double | 0 | 71 | | max | Maximal value. The difference between min and max will provide the number of stars. | Double | 5 | 72 | | step | Step size. | Double | 0.5 | 73 | | read-only | Whether or not is readonly. | Boolean | false | 74 | | pristine | Whether or not the current value is the initial value. | Boolean | true | 75 | | resetable | When not readonly, whether to show the reset button. | Boolean | true | 76 | | star-width | Width of the star picture. | Integer | 16 | 77 | | star-height | Height of the star picture. | Integer | 16 | 78 | | cancel-width | Width of the cancel icon. | Integer | star-width | 79 | | cancel-height | Height of the cancel icon. | Integer | star-height | 80 | | rated | Fired when a rating happened. (Obtain the rated value by the model) | Function | - | 81 | | reset | Fired when the reset button was clicked. | Function | - | 82 | | before-rated | Fired before the item is actually rated. By rejecting the promise it is possible to cancel the rating. | Function: return promise | - | 83 | | before-reset | Fired before the item is actually reset. By rejecting the promise it is possible to cancel the reset. | Function: return promise | - | 84 | 85 | 86 | ### Customization 87 | 88 | You can easily add your own star style via css. You can use the star-width and star-height attributes to make the 'stars' bigger if necessary. 89 | 90 | ```html 91 | 96 | 97 | ``` 98 | 99 | ### Release Note: 100 | 101 | V4.0.0 102 | 103 | * BREAKING: The callback function binding has changed form two-way to method binding. This will allow you to pass your own variables to the callback function AND the current rating is passed in the `rating` parameter: 104 | ```html 105 | 106 | ``` 107 | ```js 108 | $scope.myCallback = function (rating, cusotmVar) { 109 | console.log(rating, customVar); 110 | } 111 | ``` 112 | To upgrade from v3 to v4, just add `()` after your function name. 113 | 114 | 115 | V3.0.0 116 | 117 | * BREAKING: The `over` callback is removed. 118 | * BREAKING: If you're using your own template, you need to update it. 119 | * Template and CSS file are refactored in order to support mobile divices. 120 | * Moved calculations from template to controller. 121 | 122 | # MIT License 123 | 124 | Copyright (c) 2017 Arjan Kempes 125 | 126 | Permission is hereby granted, free of charge, to any person obtaining a copy 127 | of this software and associated documentation files (the "Software"), to deal 128 | in the Software without restriction, including without limitation the rights 129 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 130 | copies of the Software, and to permit persons to whom the Software is 131 | furnished to do so, subject to the following conditions: 132 | 133 | The above copyright notice and this permission notice shall be included in all 134 | copies or substantial portions of the Software. 135 | 136 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 137 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 138 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 139 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 140 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 141 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 142 | SOFTWARE. 143 | 144 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-rateit", 3 | "version": "4.0.2", 4 | "homepage": "https://github.com/akempes/angular-rateit", 5 | "authors": [ 6 | "Arjan Kempes " 7 | ], 8 | "description": "Angular (star)rating directive without any other dependecies nor jQuery. Inspired by jQuery RateIt.", 9 | "main": [ 10 | "dist/ng-rateit.js", 11 | "dist/ng-rateit.css" 12 | ], 13 | "ignore": [], 14 | "dependencies": { 15 | "angular": ">=1.2.0" 16 | }, 17 | "main": [ 18 | "dist/ng-rateit.css", 19 | "dist/ng-rateit.min.js" 20 | ], 21 | "keywords": [ 22 | "Angular", 23 | "rating", 24 | "stars", 25 | "starrating" 26 | ], 27 | "license": "MIT" 28 | } 29 | -------------------------------------------------------------------------------- /dist/ng-rateit.css: -------------------------------------------------------------------------------- 1 | .ngrateit-rating{display:inline-block;overflow:hidden}.ngrateit-reset{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxhYWdfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHdpZHRoPSIxNnB4IiBoZWlnaHQ9IjMycHgiIHZpZXdCb3g9IjAgMCAxNiAzMiIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTYgMzIiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0IzQjNCMyIgZD0iTTgsMi4xNzRjLTMuMjE5LDAtNS44MjcsMi42MDktNS44MjcsNS44MjdTNC43ODMsMTMuODI2LDgsMTMuODI2YzMuMjE4LDAsNS44MjYtMi42MDcsNS44MjYtNS44MjUNCglTMTEuMjE5LDIuMTc0LDgsMi4xNzR6IE0xMS40MzgsOUg0LjU2M1Y3aDYuODc0Vjl6Ii8+DQo8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzFfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0xMjIuMzI2NyIgeTE9IjgwMCIgeDI9Ii0xMTAuNjczOCIgeTI9IjgwMCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxIDAgMCAxIDEyNC41IC03NzYpIj4NCgk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojRkYxRDI1Ii8+DQoJPHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6I0Q3MDAyRSIvPg0KPC9saW5lYXJHcmFkaWVudD4NCjxwYXRoIGZpbGw9InVybCgjU1ZHSURfMV8pIiBkPSJNOCwxOC4xNzRjLTMuMjE5LDAtNS44MjcsMi42MDktNS44MjcsNS44MjdTNC43ODMsMjkuODI2LDgsMjkuODI2YzMuMjE4LDAsNS44MjYtMi42MDcsNS44MjYtNS44MjUNCglTMTEuMjE5LDE4LjE3NCw4LDE4LjE3NHogTTExLjQzOCwyNUg0LjU2M3YtMmg2Ljg3NFYyNXoiLz4NCjwvc3ZnPg0K);display:inline-block;background-position:0 0}.ngrateit-reset:hover{background-position:0 100%}.ngrateit-star{display:block;float:left;overflow:hidden;background-repeat:repeat-x}.ngrateit-bg-star{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxhYWdfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHdpZHRoPSIxNnB4IiBoZWlnaHQ9IjE2cHgiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTYgMTYiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8zXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIwLjIwNyIgeTE9IjgiIHgyPSIxNS43OTIiIHkyPSI4Ij4NCgk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojQ0NDQ0NDIi8+DQoJPHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6I0U2RTZFNiIvPg0KPC9saW5lYXJHcmFkaWVudD4NCjxwYXRoIGZpbGw9InVybCgjU1ZHSURfM18pIiBkPSJNOC4zNjcsMC44MTRsMS45ODQsNC42OTFsNS4wNzQsMC40MzRjMC4zNTIsMC4wMzEsMC40OTYsMC40NzMsMC4yMjcsMC43MDNsLTMuODQ4LDMuMzM2bDEuMTUyLDQuOTYxDQoJYzAuMDgyLDAuMzQ0LTAuMjkzLDAuNjE3LTAuNTk0LDAuNDM0TDgsMTIuNzRsLTQuMzYzLDIuNjMzYy0wLjMwMSwwLjE4LTAuNjc2LTAuMDktMC41OTQtMC40MzRsMS4xNTItNC45NjFMMC4zNDQsNi42NDINCglDMC4wNzgsNi40MDgsMC4yMjMsNS45NywwLjU3NCw1LjkzOWw1LjA3NC0wLjQzNGwxLjk4NS00LjY5MUM3Ljc2OSwwLjQ4Niw4LjIzLDAuNDg2LDguMzY3LDAuODE0TDguMzY3LDAuODE0eiBNOC4zNjcsMC44MTQiLz4NCjwvc3ZnPg0K)}.ngrateit-selected{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxhYWdfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHdpZHRoPSIxNnB4IiBoZWlnaHQ9IjE2cHgiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTYgMTYiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8zXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIwLjIwNyIgeTE9IjgiIHgyPSIxNS43OTIiIHkyPSI4Ij4NCgk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojRkJCMDNCIi8+DQoJPHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6I0ZGOTQyRCIvPg0KPC9saW5lYXJHcmFkaWVudD4NCjxwYXRoIGZpbGw9InVybCgjU1ZHSURfM18pIiBkPSJNOC4zNjcsMC44MTRsMS45ODQsNC42OTFsNS4wNzQsMC40MzRjMC4zNTIsMC4wMzEsMC40OTYsMC40NzMsMC4yMjcsMC43MDNsLTMuODQ4LDMuMzM2bDEuMTUyLDQuOTYxDQoJYzAuMDgyLDAuMzQ0LTAuMjkzLDAuNjE3LTAuNTk0LDAuNDM0TDgsMTIuNzRsLTQuMzYzLDIuNjMzYy0wLjMwMSwwLjE4LTAuNjc2LTAuMDktMC41OTQtMC40MzRsMS4xNTItNC45NjFMMC4zNDQsNi42NDINCglDMC4wNzgsNi40MDgsMC4yMjMsNS45NywwLjU3NCw1LjkzOWw1LjA3NC0wLjQzNGwxLjk4NS00LjY5MUM3Ljc2OSwwLjQ4Niw4LjIzLDAuNDg2LDguMzY3LDAuODE0TDguMzY3LDAuODE0eiBNOC4zNjcsMC44MTQiLz4NCjwvc3ZnPg0K)}.ngrateit:not(.ngrateit-readonly) .ngrateit-hashover.ngrateit-rating span:hover~span{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxhYWdfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHdpZHRoPSIxNnB4IiBoZWlnaHQ9IjE2cHgiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTYgMTYiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8zXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIwLjIwNyIgeTE9IjgiIHgyPSIxNS43OTIiIHkyPSI4Ij4NCgk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojQ0NDQ0NDIi8+DQoJPHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6I0U2RTZFNiIvPg0KPC9saW5lYXJHcmFkaWVudD4NCjxwYXRoIGZpbGw9InVybCgjU1ZHSURfM18pIiBkPSJNOC4zNjcsMC44MTRsMS45ODQsNC42OTFsNS4wNzQsMC40MzRjMC4zNTIsMC4wMzEsMC40OTYsMC40NzMsMC4yMjcsMC43MDNsLTMuODQ4LDMuMzM2bDEuMTUyLDQuOTYxDQoJYzAuMDgyLDAuMzQ0LTAuMjkzLDAuNjE3LTAuNTk0LDAuNDM0TDgsMTIuNzRsLTQuMzYzLDIuNjMzYy0wLjMwMSwwLjE4LTAuNjc2LTAuMDktMC41OTQtMC40MzRsMS4xNTItNC45NjFMMC4zNDQsNi42NDINCglDMC4wNzgsNi40MDgsMC4yMjMsNS45NywwLjU3NCw1LjkzOWw1LjA3NC0wLjQzNGwxLjk4NS00LjY5MUM3Ljc2OSwwLjQ4Niw4LjIzLDAuNDg2LDguMzY3LDAuODE0TDguMzY3LDAuODE0eiBNOC4zNjcsMC44MTQiLz4NCjwvc3ZnPg0K)}.ngrateit:not(.ngrateit-readonly) .ngrateit-hashover.ngrateit-rating:hover span{cursor:pointer;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxhYWdfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHdpZHRoPSIxNnB4IiBoZWlnaHQ9IjE2cHgiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTYgMTYiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8zXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIwLjIwNyIgeTE9IjgiIHgyPSIxNS43OTIiIHkyPSI4Ij4NCgk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojRkYxRDI1Ii8+DQoJPHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6I0Q3MDAyRSIvPg0KPC9saW5lYXJHcmFkaWVudD4NCjxwYXRoIGZpbGw9InVybCgjU1ZHSURfM18pIiBkPSJNOC4zNjcsMC44MTRsMS45ODQsNC42OTFsNS4wNzQsMC40MzRjMC4zNTIsMC4wMzEsMC40OTYsMC40NzMsMC4yMjcsMC43MDNsLTMuODQ4LDMuMzM2bDEuMTUyLDQuOTYxDQoJYzAuMDgyLDAuMzQ0LTAuMjkzLDAuNjE3LTAuNTk0LDAuNDM0TDgsMTIuNzRsLTQuMzYzLDIuNjMzYy0wLjMwMSwwLjE4LTAuNjc2LTAuMDktMC41OTQtMC40MzRsMS4xNTItNC45NjFMMC4zNDQsNi42NDINCglDMC4wNzgsNi40MDgsMC4yMjMsNS45NywwLjU3NCw1LjkzOWw1LjA3NC0wLjQzNGwxLjk4NS00LjY5MUM3Ljc2OSwwLjQ4Niw4LjIzLDAuNDg2LDguMzY3LDAuODE0TDguMzY3LDAuODE0eiBNOC4zNjcsMC44MTQiLz4NCjwvc3ZnPg0K)} -------------------------------------------------------------------------------- /dist/ng-rateit.js: -------------------------------------------------------------------------------- 1 | angular.module('ngRateIt', ['ng']) 2 | .directive('ngRateIt', ["$q", function( $q ) { 3 | 'use strict'; 4 | 5 | /*jslint unparam:true */ 6 | var link = function ($scope, $element, $attrs) { 7 | 8 | if(!$attrs.readOnly){ 9 | $scope.readOnly = function(){return false;}; 10 | } 11 | 12 | if(!$attrs.resetable){ 13 | $scope.resetable = function(){return true;}; 14 | } 15 | 16 | if(!$attrs.beforeRated){ 17 | $scope.beforeRated = function(){var d = $q.defer(); d.resolve(); return d.promise;}; 18 | } 19 | 20 | if(!$attrs.rated){ 21 | $scope.rated = function(){return;}; 22 | } 23 | 24 | if(!$attrs.beforeReset){ 25 | $scope.beforeReset = function(){var d = $q.defer(); d.resolve(); return d.promise;}; 26 | } 27 | 28 | if(!$attrs.reset){ 29 | $scope.reset = function(){return;}; 30 | } 31 | 32 | }; 33 | /*jslint unparam:false */ 34 | 35 | return { 36 | scope:{ 37 | ngModel : '=', 38 | min : '=?min', 39 | max : '=?max', 40 | step : '=?step', 41 | readOnly : '&?readOnly', 42 | pristine : '=?pristine', 43 | resetable : '&?resetable', 44 | starWidth : '=?starWidth', 45 | starHeight : '=?starHeight', 46 | canelWidth : '=?canelWidth', 47 | cancelHeight : '=?cancelHeight', 48 | rated : '&?rated', 49 | reset : '&?reset', 50 | beforeRated : '&?beforeRated', 51 | beforeReset : '&?beforeReset' 52 | }, 53 | templateUrl: 'ngRateIt/ng-rate-it.html', 54 | require: 'ngModel', 55 | replace: true, 56 | link: link, 57 | controller: 'ngRateItController' 58 | }; 59 | 60 | }]) 61 | .controller('ngRateItController', ["$scope", "$timeout", function ( $scope, $timeout ) { 62 | 'use strict'; 63 | 64 | $scope.isTouch = !! window.hasOwnProperty("ontouchstart") || window.navigator.msMaxTouchPoints > 0; 65 | $scope.orgValue = angular.copy($scope.ngModel); 66 | 67 | $scope.min = $scope.min || 0; 68 | $scope.max = $scope.max || 5; 69 | $scope.step = $scope.step || 0.5; 70 | 71 | $scope.pristine = $scope.orgValue === $scope.ngModel; 72 | 73 | $scope.starWidth = $scope.starWidth || 16; 74 | $scope.starPartWidth = $scope.starWidth * $scope.step; 75 | $scope.starHeight = $scope.starHeight || 16; 76 | $scope.canelWidth = $scope.canelWidth || $scope.starWidth; 77 | $scope.cancelHeight = $scope.cancelHeight || $scope.starHeight; 78 | 79 | var diff = $scope.max - $scope.min, 80 | steps = diff / $scope.step, 81 | garbage = $scope.$watch('ngModel', function () { 82 | $scope.pristine = $scope.orgValue === $scope.ngModel; 83 | }), 84 | 85 | getValue = function (index) { 86 | return (index+1) / steps * diff; 87 | }; 88 | 89 | $scope.getStartParts = function () { 90 | return new Array(steps); 91 | }; 92 | 93 | $scope.getStarOffset = function (index) { 94 | var ratio = 1/$scope.step, 95 | offset = -($scope.starWidth/ratio)*(index%ratio); 96 | return offset; 97 | }; 98 | 99 | $scope.isSelected = function (index) { 100 | return getValue(index) <= $scope.ngModel-$scope.min; 101 | }; 102 | 103 | $scope.removeRating = function () { 104 | if ($scope.resetable() && !$scope.readOnly()) { 105 | $scope.beforeReset({rating:$scope.ngModel}).then(function () { 106 | $scope.ngModel = $scope.min; 107 | $scope.reset({rating:$scope.ngModel}); 108 | }); 109 | } 110 | }; 111 | 112 | $scope.setValue = function (index) { 113 | if (!$scope.readOnly()) { 114 | var tmpValue = angular.copy($scope.min + getValue(index)); 115 | 116 | $scope.beforeRated({rating:tmpValue}).then(function () { 117 | $scope.ngModel = tmpValue; 118 | $timeout(function () { 119 | $scope.rated({rating:$scope.ngModel}); 120 | }); 121 | }); 122 | } 123 | }; 124 | 125 | $scope.$on('$destroy', function () { 126 | garbage(); 127 | }); 128 | 129 | }]) 130 | .run(['$templateCache', function ($templateCache) { 131 | 'use strict'; 132 | 133 | $templateCache.put('ngRateIt/ng-rate-it.html', 134 | 135 | '
' + 136 | 137 | '' + 143 | 144 | '
' + 145 | '' + 152 | '
' + 153 | '
' 154 | 155 | ); 156 | 157 | }]); 158 | 159 | -------------------------------------------------------------------------------- /dist/ng-rateit.min.js: -------------------------------------------------------------------------------- 1 | angular.module("ngRateIt",["ng"]).directive("ngRateIt",["$q",function(a){"use strict";var b=function(b,c,d){d.readOnly||(b.readOnly=function(){return!1}),d.resetable||(b.resetable=function(){return!0}),d.beforeRated||(b.beforeRated=function(){var b=a.defer();return b.resolve(),b.promise}),d.rated||(b.rated=function(){}),d.beforeReset||(b.beforeReset=function(){var b=a.defer();return b.resolve(),b.promise}),d.reset||(b.reset=function(){})};return{scope:{ngModel:"=",min:"=?min",max:"=?max",step:"=?step",readOnly:"&?readOnly",pristine:"=?pristine",resetable:"&?resetable",starWidth:"=?starWidth",starHeight:"=?starHeight",canelWidth:"=?canelWidth",cancelHeight:"=?cancelHeight",rated:"&?rated",reset:"&?reset",beforeRated:"&?beforeRated",beforeReset:"&?beforeReset"},templateUrl:"ngRateIt/ng-rate-it.html",require:"ngModel",replace:!0,link:b,controller:"ngRateItController"}}]).controller("ngRateItController",["$scope","$timeout",function(a,b){"use strict";a.isTouch=!!window.hasOwnProperty("ontouchstart")||window.navigator.msMaxTouchPoints>0,a.orgValue=angular.copy(a.ngModel),a.min=a.min||0,a.max=a.max||5,a.step=a.step||.5,a.pristine=a.orgValue===a.ngModel,a.starWidth=a.starWidth||16,a.starPartWidth=a.starWidth*a.step,a.starHeight=a.starHeight||16,a.canelWidth=a.canelWidth||a.starWidth,a.cancelHeight=a.cancelHeight||a.starHeight;var c=a.max-a.min,d=c/a.step,e=a.$watch("ngModel",function(){a.pristine=a.orgValue===a.ngModel}),f=function(a){return(a+1)/d*c};a.getStartParts=function(){return new Array(d)},a.getStarOffset=function(b){var c=1/a.step,d=-(a.starWidth/c)*(b%c);return d},a.isSelected=function(b){return f(b)<=a.ngModel-a.min},a.removeRating=function(){a.resetable()&&!a.readOnly()&&a.beforeReset({rating:a.ngModel}).then(function(){a.ngModel=a.min,a.reset({rating:a.ngModel})})},a.setValue=function(c){if(!a.readOnly()){var d=angular.copy(a.min+f(c));a.beforeRated({rating:d}).then(function(){a.ngModel=d,b(function(){a.rated({rating:a.ngModel})})})}},a.$on("$destroy",function(){e()})}]).run(["$templateCache",function(a){"use strict";a.put("ngRateIt/ng-rate-it.html",'
")}]); -------------------------------------------------------------------------------- /example/bg-car.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 11 | 12 | 13 | 14 | CCCCCC 15 | 16 | -------------------------------------------------------------------------------- /example/cancel-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /example/custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akempes/angular-rateit/33992c2ab38bcd064087ff02a4c60e1ea1f77e29/example/custom.png -------------------------------------------------------------------------------- /example/custom.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akempes/angular-rateit/33992c2ab38bcd064087ff02a4c60e1ea1f77e29/example/custom.psd -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | /*global alert, confirm*/ 2 | 3 | var myApp = angular.module('exampleApp',['ngRateIt']); 4 | 5 | myApp.controller('ExampleController', ['$scope', '$q', '$timeout', function($scope, $q, $timeout){ 6 | 'use strict'; 7 | 8 | $scope.model = { 9 | basic: 0, 10 | readonly: 2.5, 11 | readonly_enables: true, 12 | minMaxStep:6, 13 | minMaxStep2:8.75, 14 | pristine: 3, 15 | resetable: 1, 16 | heightWidth: 1.5, 17 | callbacks: 5, 18 | custom: 4, 19 | }; 20 | 21 | $scope.ratedCallback = function (rating) { 22 | alert('The rated value is: '+ rating); 23 | console.log('The rated value is: '+ rating); 24 | }; 25 | 26 | $scope.resetCallback = function () { 27 | alert('Reset clicked!'); 28 | console.log('Reset clicked!'); 29 | }; 30 | 31 | $scope.confirmReset = function () { 32 | var d = $q.defer(); 33 | if(confirm('Are you sure about resetting this rating?')){ 34 | d.resolve(); 35 | }else{ 36 | d.reject(); 37 | } 38 | return d.promise; 39 | }; 40 | 41 | $scope.confirmRating = function (newRating, cusotmVar) { 42 | var d = $q.defer(); 43 | 44 | $timeout(function () { 45 | if(confirm('Are you sure about rating us with '+newRating+' '+cusotmVar+'?')){ 46 | d.resolve(); 47 | }else{ 48 | d.reject(); 49 | } 50 | }); 51 | 52 | return d.promise; 53 | }; 54 | 55 | $scope.confirmReset = function () { 56 | var d = $q.defer(); 57 | if(confirm('Are you sure about resetting this rating?')){ 58 | d.resolve(); 59 | }else{ 60 | d.reject(); 61 | } 62 | return d.promise; 63 | }; 64 | 65 | } 66 | ]); 67 | 68 | 69 | -------------------------------------------------------------------------------- /example/hover-car.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 23 | 24 |

Basic

25 |
26 | 27 |

Value: {{model.basic}}

28 |
29 |
30 | 31 |

Min, Max & step

32 |
33 | 34 |

Value: {{model.minMaxStep}}

35 |
36 |
37 |
38 | 39 |

Value: {{model.minMaxStep2}}

40 |
41 |
42 | 43 |

Read only

44 |
45 | 46 |
47 |

Value: {{model.readonly}}

48 |

 49 | 
50 |
51 | 52 |

Is pristine

53 |
54 | 55 |

Value: {{model.pristine}}

56 |

Is pristine: {{model.resetable_pristine ? 'Yes' : 'No'}}

57 |
58 |
59 | 60 |

No reset

61 |
62 | 63 |

Value: {{model.resetable}}

64 |
65 |
66 | 67 |

Start height/width

68 |
69 | 74 | 75 |

Value: {{model.heightWidth}}

76 |
 77 | 
 82 | 
 83 | 
84 |
85 | 86 |

Callbacks

87 |
88 | 89 |

Value: {{model.resetable}}

90 |
91 |
92 | 93 |

Custom image

94 |
95 | 117 | 118 |

Value: {{model.custom}}

119 |
120 | 
142 | 
143 | 
144 | 145 |
146 | 147 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /example/ng-rate-it.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 9 | 10 |
11 | 18 |
19 | 20 |
-------------------------------------------------------------------------------- /example/rated-car.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ng-rate-it.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akempes/angular-rateit/33992c2ab38bcd064087ff02a4c60e1ea1f77e29/ng-rate-it.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-rateit", 3 | "version": "4.0.2", 4 | "scripts": { 5 | "build": "grunt build", 6 | "deploy": "grunt deploy-patch" 7 | }, 8 | "main": [ 9 | "dist/ng-rateit.css", 10 | "dist/ng-rateit.min.js" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/akempes/angular-rateit.git" 15 | }, 16 | "devDependencies": { 17 | "grunt": "^0.4.5", 18 | "grunt-cli": "^1.2.0", 19 | "grunt-contrib-clean": "^0.5.0", 20 | "grunt-contrib-copy": "^1.0.0", 21 | "grunt-contrib-cssmin": "^0.9.0", 22 | "grunt-contrib-uglify": "^0.4.0", 23 | "grunt-gh-pages": "^1.1.0", 24 | "grunt-image-embed": "^0.3.3", 25 | "grunt-jslint": "~1.1.12", 26 | "grunt-ng-annotate": "~0.7.0", 27 | "grunt-remove-logging": "~0.2.0", 28 | "grunt-replace": "^1.0.1", 29 | "grunt-version": "^1.1.1", 30 | "load-grunt-tasks": "^0.4.0" 31 | }, 32 | "engines": { 33 | "node": ">=0.10.0" 34 | }, 35 | "license": "MIT" 36 | } 37 | -------------------------------------------------------------------------------- /src/images/bg-star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /src/images/cancel-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | -------------------------------------------------------------------------------- /src/images/hover-star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /src/images/rated-star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /src/ng-rateit.js: -------------------------------------------------------------------------------- 1 | angular.module('ngRateIt', ['ng']) 2 | .directive('ngRateIt', ["$q", function( $q ) { 3 | 'use strict'; 4 | 5 | /*jslint unparam:true */ 6 | var link = function ($scope, $element, $attrs) { 7 | 8 | if(!$attrs.readOnly){ 9 | $scope.readOnly = function(){return false;}; 10 | } 11 | 12 | if(!$attrs.resetable){ 13 | $scope.resetable = function(){return true;}; 14 | } 15 | 16 | if(!$attrs.beforeRated){ 17 | $scope.beforeRated = function(){var d = $q.defer(); d.resolve(); return d.promise;}; 18 | } 19 | 20 | if(!$attrs.rated){ 21 | $scope.rated = function(){return;}; 22 | } 23 | 24 | if(!$attrs.beforeReset){ 25 | $scope.beforeReset = function(){var d = $q.defer(); d.resolve(); return d.promise;}; 26 | } 27 | 28 | if(!$attrs.reset){ 29 | $scope.reset = function(){return;}; 30 | } 31 | 32 | }; 33 | /*jslint unparam:false */ 34 | 35 | return { 36 | scope:{ 37 | ngModel : '=', 38 | min : '=?min', 39 | max : '=?max', 40 | step : '=?step', 41 | readOnly : '&?readOnly', 42 | pristine : '=?pristine', 43 | resetable : '&?resetable', 44 | starWidth : '=?starWidth', 45 | starHeight : '=?starHeight', 46 | canelWidth : '=?canelWidth', 47 | cancelHeight : '=?cancelHeight', 48 | rated : '&?rated', 49 | reset : '&?reset', 50 | beforeRated : '&?beforeRated', 51 | beforeReset : '&?beforeReset' 52 | }, 53 | templateUrl: 'ngRateIt/ng-rate-it.html', 54 | require: 'ngModel', 55 | replace: true, 56 | link: link, 57 | controller: 'ngRateItController' 58 | }; 59 | 60 | }]) 61 | .controller('ngRateItController', ["$scope", "$timeout", function ( $scope, $timeout ) { 62 | 'use strict'; 63 | 64 | $scope.isTouch = !! window.hasOwnProperty("ontouchstart") || window.navigator.msMaxTouchPoints > 0; 65 | $scope.orgValue = angular.copy($scope.ngModel); 66 | 67 | $scope.min = $scope.min || 0; 68 | $scope.max = $scope.max || 5; 69 | $scope.step = $scope.step || 0.5; 70 | 71 | $scope.pristine = $scope.orgValue === $scope.ngModel; 72 | 73 | $scope.starWidth = $scope.starWidth || 16; 74 | $scope.starPartWidth = $scope.starWidth * $scope.step; 75 | $scope.starHeight = $scope.starHeight || 16; 76 | $scope.canelWidth = $scope.canelWidth || $scope.starWidth; 77 | $scope.cancelHeight = $scope.cancelHeight || $scope.starHeight; 78 | 79 | var diff = $scope.max - $scope.min, 80 | steps = diff / $scope.step, 81 | garbage = $scope.$watch('ngModel', function () { 82 | $scope.pristine = $scope.orgValue === $scope.ngModel; 83 | }), 84 | 85 | getValue = function (index) { 86 | return (index+1) / steps * diff; 87 | }; 88 | 89 | $scope.getStartParts = function () { 90 | return new Array(steps); 91 | }; 92 | 93 | $scope.getStarOffset = function (index) { 94 | var ratio = 1/$scope.step, 95 | offset = -($scope.starWidth/ratio)*(index%ratio); 96 | return offset; 97 | }; 98 | 99 | $scope.isSelected = function (index) { 100 | return getValue(index) <= $scope.ngModel-$scope.min; 101 | }; 102 | 103 | $scope.removeRating = function () { 104 | if ($scope.resetable() && !$scope.readOnly()) { 105 | $scope.beforeReset({rating:$scope.ngModel}).then(function () { 106 | $scope.ngModel = $scope.min; 107 | $scope.reset({rating:$scope.ngModel}); 108 | }); 109 | } 110 | }; 111 | 112 | $scope.setValue = function (index) { 113 | if (!$scope.readOnly()) { 114 | var tmpValue = angular.copy($scope.min + getValue(index)); 115 | 116 | $scope.beforeRated({rating:tmpValue}).then(function () { 117 | $scope.ngModel = tmpValue; 118 | $timeout(function () { 119 | $scope.rated({rating:$scope.ngModel}); 120 | }); 121 | }); 122 | } 123 | }; 124 | 125 | $scope.$on('$destroy', function () { 126 | garbage(); 127 | }); 128 | 129 | }]) 130 | .run(['$templateCache', function ($templateCache) { 131 | 'use strict'; 132 | 133 | $templateCache.put('ngRateIt/ng-rate-it.html', 134 | 135 | '
' + 136 | 137 | '' + 143 | 144 | '
' + 145 | '' + 152 | '
' + 153 | '
' 154 | 155 | ); 156 | 157 | }]); 158 | 159 | -------------------------------------------------------------------------------- /src/star.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akempes/angular-rateit/33992c2ab38bcd064087ff02a4c60e1ea1f77e29/src/star.psd -------------------------------------------------------------------------------- /src/style/ng-rateit.css: -------------------------------------------------------------------------------- 1 | .ngrateit-rating { 2 | display: inline-block; 3 | overflow: hidden; 4 | } 5 | 6 | /* Reset button */ 7 | .ngrateit-reset{ 8 | background-image: url("../images/cancel-icon.svg"); 9 | display: inline-block; 10 | background-position: 0 0; 11 | } 12 | .ngrateit-reset:hover{ 13 | background-position: 0 100%; 14 | } 15 | 16 | /* star */ 17 | .ngrateit-star{ 18 | display: block; 19 | float: left; 20 | overflow: hidden; 21 | background-repeat: repeat-x; 22 | } 23 | 24 | /* Background */ 25 | .ngrateit-bg-star{ 26 | background-image: url("../images/bg-star.svg"); 27 | } 28 | 29 | /* Selected state */ 30 | .ngrateit-selected { 31 | background-image: url("../images/rated-star.svg"); 32 | } 33 | 34 | /* Cancelation of hover styling */ 35 | .ngrateit:not(.ngrateit-readonly) .ngrateit-hashover.ngrateit-rating span:hover ~ span { 36 | background-image: url("../images/bg-star.svg"); 37 | } 38 | 39 | /* Hover styling */ 40 | .ngrateit:not(.ngrateit-readonly) .ngrateit-hashover.ngrateit-rating:hover span { 41 | cursor: pointer; 42 | background-image: url("../images/hover-star.svg"); 43 | } 44 | --------------------------------------------------------------------------------