Angular User Feedback
by AntonLapshin
HTML
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.11/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.11/angular-animate.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-smart-table/2.1.3/smart-table.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/1.6.3/less.min.js"></script>
<section ng-app="app" ng-controller="OrderOverviewController">
<h1>
Feedback
</h1>
<div class="table-container">
<table st-table="displayedCollection" class="table table-striped user-feedback" st-pagination-scroll st-safe-src="rowCollection">
<thead>
<tr class="header">
<th st-sort="user">User</th>
<th st-sort="deceased_name">Customer</th>
<th st-sort="created_at" st-sort-default="reverse">Date</th>
<th st-sort="score">Score</th>
<th st-sort="attention">Attention</th>
</tr>
<tr>
<th>
<input st-search="user" placeholder="Search for user" class="input-sm form-control" type="search" />
</th>
<th colspan="4">
<input st-search placeholder="Global search" class="input-sm form-control" type="search" />
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="row in displayedCollection" st-select-row="row" class="{{ 'attention-' + row.attention }}">
<td>{{row.user}}</td>
<td>{{row.deceased_name | uppercase}}</td>
<td>{{row.created_at | date: 'yyyy-MM-dd'}}</td>
<td>
<feedback-rating ng-init="init(row.score)"></feedback-rating>
</td>
<td>
<feedback-attention ng-init="init(row.attention)"></feedback-attention>
</td>
</tr>
<tr...
CSS
h1 {
text-align: center;
}
.table-container {
max-height: 400px;
overflow-y: auto;
overflow-x: hidden;
position: relative;
border: 1px solid #eee;
h1,
h2,
h3,
h4,
.col-xs-4 {
text-align: center;
}
}
.st-sort-ascent:before {
content: '\25B2';
}
.st-sort-descent:before {
content: '\25BC';
}
.user-feedback {
th,
tr {
cursor: pointer;
}
thead {
background-color: #eee;
}
tbody tr {
transition: all ease 400ms;
}
tbody {
tr {
&:not(.tigerbox) {
td:first-child {
position: relative;
padding-left: 10px;
&:before {
transition: all ease 400ms;
content: '';
position: absolute;
width: 0;
height: 100%;
left: 0;
top: 0;
background-color: #1c90f3 !important;
z-index: 1;
}
}
&:hover,
&.st-selected {
td:first-child {
&:before {
width: 5px;
}
}
}
&.attention-1 {
//background-color: #a4ef8c;
}
&.attention-2 {
//background-color: orange;
}
&.attention-3 {
//background-color: tomato;
}
}
}
.improvements {
margin-top: 2em;
}
}
.tigerbox {
background-color: white !important;
}
}
/* The starting CSS styles for the enter animation */
.fade2.ng-enter {
transition: 0.5s linear all;
opacity: 0;
}
/* The finishing CSS styles for the enter animation */
.fade2.ng-enter.ng-enter-active {
opacity: 1;
}
/* Rating */
.rating {
direction: rtl;
padding-right: 0;
margin: 0;
min-width: 122px;
display: inline-block;
vertical-align: middle;
}
.rating__star {
cursor: pointer;
display: inline-block;
font-size: 22px;
height: 24px;
position: relative;
width: 24px;
}
.rating__star::before {
color: #34495e;
content: "\2605";
line-height:...
JavaScript
$('head style[type="text/css"]').attr('type', 'text/less');
less.env = 'development';
less.refreshStyles();
(function() {
var app = angular.module('app', ['smart-table', 'ngAnimate']);
app.directive('feedbackRating', function() {
return {
'restrict': 'E',
scope: true,
'template': '<ol class="rating"><li ng-repeat="star in stars | reverse" class="rating__star" ng-class="{ is_active: rating >= star }"></li></ol>',
'controller': function($scope) {
$scope.stars = [1, 2, 3, 4, 5];
$scope.rating = 0;
$scope.init = function(score) {
$scope.rating = score;
}
}
};
});
app.directive('feedbackAttention', function() {
return {
restrict: 'E',
scope: true,
template: '<svg ng-show="isShown" fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path class="color-path" d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',
controller: function($scope) {
$scope.isShown = false;
$scope.init = function(attention) {
$scope.isShown = attention === 1;
}
}
};
});
app.filter('reverse', function() {
return function(items) {
return items.slice().reverse();
};
});
angular.module('smart-table')
.directive('stPaginationScroll', ['$timeout', function(timeout) {
return {
require: 'stTable',
link: function(scope, element, attr, ctrl) {
var itemByPage = 20;
var pagination = ctrl.tableState().pagination;
var lengthThreshold = 50;
var timeThreshold = 400;
var handler = function() {
scope.callServer();
};
var promise = null;
var lastRemaining = 9999;
var container = angular.element(element.parent());
container.bind('scroll', function() {
var remaining = container[0].scrollHeight -...