Browse Source

Merge branch '1.11.x' of github.com:chamilo/chamilo-lms into 1.11.x

jmontoyaa 7 years ago
parent
commit
9ef846eaac
45 changed files with 3252 additions and 207 deletions
  1. 30 0
      app/Resources/public/assets/jquery.easy-pie-chart/.bower.json
  2. 4 0
      app/Resources/public/assets/jquery.easy-pie-chart/.gitignore
  3. 7 0
      app/Resources/public/assets/jquery.easy-pie-chart/.travis.yml
  4. 188 0
      app/Resources/public/assets/jquery.easy-pie-chart/Gruntfile.js
  5. 21 0
      app/Resources/public/assets/jquery.easy-pie-chart/LICENSE
  6. 268 0
      app/Resources/public/assets/jquery.easy-pie-chart/Readme.md
  7. 19 0
      app/Resources/public/assets/jquery.easy-pie-chart/bower.json
  8. 80 0
      app/Resources/public/assets/jquery.easy-pie-chart/changelog.md
  9. 397 0
      app/Resources/public/assets/jquery.easy-pie-chart/dist/angular.easypiechart.js
  10. 8 0
      app/Resources/public/assets/jquery.easy-pie-chart/dist/angular.easypiechart.min.js
  11. 351 0
      app/Resources/public/assets/jquery.easy-pie-chart/dist/easypiechart.js
  12. 8 0
      app/Resources/public/assets/jquery.easy-pie-chart/dist/easypiechart.min.js
  13. 360 0
      app/Resources/public/assets/jquery.easy-pie-chart/dist/jquery.easypiechart.js
  14. 8 0
      app/Resources/public/assets/jquery.easy-pie-chart/dist/jquery.easypiechart.min.js
  15. 32 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/README.tmpl.md
  16. 4 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/bagdes.md
  17. 9 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/browser-support.md
  18. 20 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/callbacks.md
  19. 1 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/credits.md
  20. 13 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/features.md
  21. 68 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/get-started.md
  22. 59 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/options.md
  23. 52 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/plugin-api.md
  24. 1 0
      app/Resources/public/assets/jquery.easy-pie-chart/docs/test.md
  25. 53 0
      app/Resources/public/assets/jquery.easy-pie-chart/karma.conf.coffee
  26. 51 0
      app/Resources/public/assets/jquery.easy-pie-chart/package.json
  27. 48 0
      app/Resources/public/assets/jquery.easy-pie-chart/src/angular.directive.js
  28. 134 0
      app/Resources/public/assets/jquery.easy-pie-chart/src/easypiechart.js
  29. 10 0
      app/Resources/public/assets/jquery.easy-pie-chart/src/jquery.plugin.js
  30. 190 0
      app/Resources/public/assets/jquery.easy-pie-chart/src/renderer/canvas.js
  31. 22 0
      app/Resources/public/assets/jquery.easy-pie-chart/test/polyfills/bind.js
  32. 68 0
      app/Resources/public/assets/jquery.easy-pie-chart/test/unit/angular.directive.js
  33. 61 0
      app/Resources/public/assets/jquery.easy-pie-chart/test/unit/jquery.js
  34. 108 0
      app/Resources/public/css/base.css
  35. 3 2
      bower.json
  36. BIN
      main/img/icons/128/skill_acquirers.png
  37. BIN
      main/img/icons/16/skill_acquirers.png
  38. BIN
      main/img/icons/22/skill_acquirers.png
  39. BIN
      main/img/icons/32/skill_acquirers.png
  40. BIN
      main/img/icons/48/skill_acquirers.png
  41. BIN
      main/img/icons/64/skill_acquirers.png
  42. 103 160
      main/mySpace/index.php
  43. 15 18
      main/mySpace/student.php
  44. 77 27
      main/mySpace/users.php
  45. 301 0
      main/template/default/my_space/index.tpl

+ 30 - 0
app/Resources/public/assets/jquery.easy-pie-chart/.bower.json

@@ -0,0 +1,30 @@
+{
+  "name": "jquery.easy-pie-chart",
+  "version": "2.1.6",
+  "main": [
+    "dist/jquery.easypiechart.js"
+  ],
+  "ignore": [
+    "demo",
+    ".editorconfig"
+  ],
+  "dependencies": {
+    "jquery": ">=1.9.0",
+    "requirejs": "~2.1.10"
+  },
+  "devDependencies": {
+    "angular": "~1.2.9",
+    "angular-mocks": "~1.2.9"
+  },
+  "homepage": "https://github.com/rendro/easy-pie-chart",
+  "_release": "2.1.6",
+  "_resolution": {
+    "type": "version",
+    "tag": "2.1.6",
+    "commit": "29636bc1cc0ecbd8de9490525724a12dbf723888"
+  },
+  "_source": "https://github.com/rendro/easy-pie-chart.git",
+  "_target": "^2.1.6",
+  "_originalSource": "jquery.easy-pie-chart",
+  "_direct": true
+}

+ 4 - 0
app/Resources/public/assets/jquery.easy-pie-chart/.gitignore

@@ -0,0 +1,4 @@
+node_modules
+bower_components
+.grunt
+_SpecRunner.html

+ 7 - 0
app/Resources/public/assets/jquery.easy-pie-chart/.travis.yml

@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+  - "0.10"
+before_install:
+  - npm install -g karma bower grunt-cli
+  - bower install
+  - npm install

+ 188 - 0
app/Resources/public/assets/jquery.easy-pie-chart/Gruntfile.js

@@ -0,0 +1,188 @@
+module.exports = function(grunt) {
+
+	grunt.initConfig({
+
+		pkg: grunt.file.readJSON('package.json'),
+
+		cfg: {
+			filename: 'easypiechart',
+			vanillaExportName: 'EasyPieChart'
+		},
+
+		dirs: {
+			tmp: 'tmp',
+			src: 'src',
+			dest: 'dist',
+			docs: 'docs',
+			test: 'test',
+			demo: 'demo'
+		},
+
+		clean: {
+			all: ['<%= dirs.dest %>/', '<%= dirs.tmp %>/'],
+			tmp: ['<%= dirs.tmp %>/']
+		},
+
+		concat: {
+			vanilla: {
+				src: [
+					'<%= dirs.src %>/renderer/canvas.js',
+					'<%= dirs.src %>/<%= cfg.filename %>.js'
+				],
+				dest: '<%= dirs.tmp %>/<%= cfg.filename %>.js'
+			},
+			jquery: {
+				src: [
+					'<%= dirs.src %>/renderer/canvas.js',
+					'<%= dirs.src %>/<%= cfg.filename %>.js',
+					'<%= dirs.src %>/jquery.plugin.js'
+				],
+				dest: '<%= dirs.tmp %>/jquery.<%= cfg.filename %>.js'
+			},
+			angular: {
+				src: [
+					'<%= dirs.src %>/angular.directive.js',
+					'<%= dirs.src %>/renderer/canvas.js',
+					'<%= dirs.src %>/<%= cfg.filename %>.js'
+				],
+				dest: '<%= dirs.tmp %>/angular.<%= cfg.filename %>.js'
+			}
+		},
+
+		usebanner: {
+			options: {
+				position: 'top',
+				banner: '/**!\n' +
+						' * <%= pkg.name %>\n' +
+						' * <%= pkg.description %>\n' +
+						' *\n' +
+						' * @license <%= pkg.license %>\n'+
+						' * @author <%= pkg.author.name %> <<%= pkg.author.email %>> (<%= pkg.author.url %>)\n' +
+						' * @version <%= pkg.version %>\n' +
+						' **/\n'
+			},
+			files: {
+				src: [
+					'<%= dirs.dest %>/<%= cfg.filename %>.js',
+					'<%= dirs.dest %>/jquery.<%= cfg.filename %>.js',
+					'<%= dirs.dest %>/angular.<%= cfg.filename %>.js'
+				]
+			}
+		},
+
+		uglify: {
+			dist: {
+				options: {
+					report: 'gzip',
+					preserveComments: 'some'
+				},
+				files: {
+					'dist/<%= cfg.filename %>.min.js': ['dist/<%= cfg.filename %>.js'],
+					'dist/jquery.<%= cfg.filename %>.min.js': ['dist/jquery.<%= cfg.filename %>.js'],
+					'dist/angular.<%= cfg.filename %>.min.js': ['dist/angular.<%= cfg.filename %>.js']
+				}
+			}
+		},
+
+		watch: {
+			gruntfile: {
+				files: ['Gruntfile.js']
+			},
+			scripts: {
+				files: '<%= dirs.src %>/**/*.js',
+				tasks: ['default'],
+				options: {
+					debounceDelay: 250
+				}
+			},
+			less: {
+				files: '<%= dirs.demo %>/*.less',
+				tasks: ['less'],
+				options: {
+					debounceDelay: 250
+				}
+			},
+			readme: {
+				files: '<%= dirs.docs %>/**/*.md',
+				tasks: ['readme'],
+				options: {
+					debounceDelay: 250
+				}
+			}
+		},
+
+		jshint: {
+			files: [
+				'<%= dirs.src %>/**/*.js',
+				'<%= dirs.test %>/**/*.js'
+			],
+			options: {}
+		},
+
+		karma: {
+			unit: {
+				configFile: 'karma.conf.coffee'
+			},
+			ci: {
+				configFile: 'karma.conf.coffee',
+				singleRun: true,
+				browsers: ['PhantomJS']
+			}
+		},
+
+		less: {
+			demo: {
+				files: {
+					'<%= dirs.demo %>/style.css': ['<%= dirs.demo %>/style.less']
+				}
+			}
+		},
+
+		umd: {
+			vanilla: {
+				src: '<%= dirs.tmp %>/<%= cfg.filename %>.js',
+				dest: '<%= dirs.dest %>/<%= cfg.filename %>.js',
+				objectToExport: '<%= cfg.vanillaExportName %>',
+				globalAlias: '<%= cfg.vanillaExportName %>'
+			},
+			jquery: {
+				src: '<%= dirs.tmp %>/jquery.<%= cfg.filename %>.js',
+				dest: '<%= dirs.dest %>/jquery.<%= cfg.filename %>.js',
+				deps: {
+					'default': ['$'],
+					amd: ['jquery'],
+					cjs: ['jquery'],
+					global: ['jQuery']
+				}
+			},
+			angular: {
+				src: '<%= dirs.tmp %>/angular.<%= cfg.filename %>.js',
+				dest: '<%= dirs.dest %>/angular.<%= cfg.filename %>.js',
+				deps: {
+					'default': ['angular'],
+					amd: ['angular'],
+					cjs: ['angular'],
+					global: ['angular']
+				}
+			}
+		}
+	});
+
+	// load all installed grunt tasks
+	require('load-grunt-tasks')(grunt);
+
+	// task defiinitions
+	grunt.registerTask('default', [
+		'clean:all',
+		'jshint',
+		'concat',
+		'umd',
+		'usebanner',
+		'uglify',
+		'clean:tmp',
+		'readme'
+	]);
+
+	grunt.registerTask('test', ['karma:unit']);
+	grunt.registerTask('all', ['default', 'less']);
+};

+ 21 - 0
app/Resources/public/assets/jquery.easy-pie-chart/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Robert Fleischmann
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 268 - 0
app/Resources/public/assets/jquery.easy-pie-chart/Readme.md

@@ -0,0 +1,268 @@
+# easyPieChart
+
+> Lightweight plugin to render simple, animated and retina optimized pie charts
+
+![Version](http://img.shields.io/version/2.1.6.png?color=green)
+[![Build Status](https://travis-ci.org/rendro/easy-pie-chart.png)](https://travis-ci.org/rendro/easy-pie-chart)
+[![Dependencies Status](https://david-dm.org/rendro/easy-pie-chart/dev-status.png)](https://david-dm.org/rendro/easy-pie-chart)
+[![Analytics](https://ga-beacon.appspot.com/UA-46840672-1/easy-pie-chart/readme)](https://github.com/igrigorik/ga-beacon)
+
+
+
+## Features
+[![](https://github.com/rendro/easy-pie-chart/raw/master/demo/img/easy-pie-chart.png)](http://drbl.in/ezuc)
+
+* highly customizable
+* very easy to implement
+* resolution independent (retina optimized)
+* uses `requestAnimationFrame` for smooth animations on modern devices and
+* works in all modern browsers, even in IE7+ with [excanvas](https://code.google.com/p/explorercanvas/wiki/Instructions)
+
+#### framework support
+
+* Vanilla JS *(no dependencies)* (~872 bytes)
+* jQuery plugin (~921 bytes)
+* Angular Module (~983 bytes)
+
+
+
+## Get started
+#### Installation
+
+You can also use [bower](http://bower.io) to install the component:
+
+```
+$ bower install jquery.easy-pie-chart
+```
+
+#### jQuery
+
+To use the easy pie chart plugin you need to load the current version of jQuery (> 1.6.4) and the source of the plugin.
+
+```html
+<div class="chart" data-percent="73" data-scale-color="#ffb400">73%</div>
+
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
+<script src="/path/to/jquery.easy-pie-chart.js"></script>
+<script>
+    $(function() {
+        $('.chart').easyPieChart({
+            //your options goes here
+        });
+    });
+</script>
+```
+
+#### Vanilla JS
+
+If you don't want to use jQuery, implement the Vanilla JS version without any dependencies.
+
+```html
+<div class="chart" data-percent="73">73%</div>
+
+<script src="/path/to/easy-pie-chart.js"></script>
+<script>
+    var element = document.querySelector('.chart');
+    new EasyPieChart(element, {
+        // your options goes here
+    });
+</script>
+```
+
+#### AngularJS
+
+```html
+<div ng-controller="chartCtrl">
+    <div easypiechart options="options" percent="percent"></div>
+</div>
+
+<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
+<script src="../dist/angular.easypiechart.min.js"></script>
+<script>
+    var app = angular.module('app', ['easypiechart']);
+    app.controller('chartCtrl', ['$scope', function ($scope) {
+        $scope.percent = 65;
+        $scope.options = {
+            animate:{
+                duration:0,
+                enabled:false
+            },
+            barColor:'#2C3E50',
+            scaleColor:false,
+            lineWidth:20,
+            lineCap:'circle'
+        };
+    }]);
+</script>
+```
+
+
+
+## Options
+You can pass these options to the initialize function to set a custom look and feel for the plugin.
+
+<table>
+    <tr>
+        <th>Property (Type)</th>
+        <th>Default</th>
+        <th>Description</th>
+    </tr>
+    <tr>
+        <td><strong>barColor</strong></td>
+        <td>#ef1e25</td>
+        <td>The color of the curcular bar. You can either pass a valid css color string, or a function that takes the current percentage as a value and returns a valid css color string.</td>
+    </tr>
+    <tr>
+        <td><strong>trackColor</strong></td>
+        <td>#f2f2f2</td>
+        <td>The color of the track, or false to disable rendering.</td>
+    </tr>
+    <tr>
+        <td><strong>scaleColor</strong></td>
+        <td>#dfe0e0</td>
+        <td>The color of the scale lines, false to disable rendering.</td>
+    </tr>
+    <tr>
+        <td><strong>scaleLength</strong></td>
+        <td>5</td>
+        <td>Length of the scale lines (reduces the radius of the chart).</td>
+    </tr>
+    <tr>
+        <td><strong>lineCap</strong></td>
+        <td>round</td>
+        <td>Defines how the ending of the bar line looks like. Possible values are: <code>butt</code>, <code>round</code> and <code>square</code>.</td>
+    </tr>
+    <tr>
+        <td><strong>lineWidth</strong></td>
+        <td>3</td>
+        <td>Width of the chart line in px.</td>
+    </tr>
+    <tr>
+        <td><strong>size</strong></td>
+        <td>110</td>
+        <td>Size of the pie chart in px. It will always be a square.</td>
+    </tr>
+        <tr>
+        <td><strong>rotate</strong></td>
+        <td>0</td>
+        <td>Rotation of the complete chart in degrees.</td>
+    </tr>
+    <tr>
+        <td><strong>animate</strong></td>
+        <td>object</td>
+        <td>Object with time in milliseconds and boolean for an animation of the bar growing (<code>{ duration: 1000, enabled: true }</code>), or false to deactivate animations.</td>
+    </tr>
+    <tr>
+        <td><strong>easing</strong></td>
+        <td>defaultEasing</td>
+        <td>Easing function or string with the name of a <a href="http://gsgd.co.uk/sandbox/jquery/easing/" target="_blank">jQuery easing function</a></td>
+    </tr>
+</table>
+
+
+
+## Callbacks
+All callbacks will only be called if `animate` is not `false`.
+
+<table>
+    <tr>
+        <th>Callback(params, ...)</th>
+        <th>Description</th>
+    </tr>
+    <tr>
+        <td><strong>onStart(from, to)</strong></td>
+        <td>Is called at the start of any animation.</td>
+    </tr>
+    <tr>
+        <td><strong>onStep(from, to, currentValue)</strong></td>
+        <td>Is called during animations providing the current value (the method is scoped to the context of th eplugin, so you can access the DOM element via <code>this.el</code>).</td>
+    </tr>
+    <tr>
+        <td><strong>onStop(from, to)</strong></td>
+        <td>Is called at the end of any animation.</td>
+    </tr>
+</table>
+
+
+
+## Plugin api
+#### jQuery
+
+```javascript
+$(function() {
+    // instantiate the plugin
+    ...
+    // update
+    $('.chart').data('easyPieChart').update(40);
+    ...
+    // disable animation
+    $('.chart').data('easyPieChart').disableAnimation();
+    ...
+    // enable animation
+    $('.chart').data('easyPieChart').enableAnimation();
+});
+```
+
+#### Vanilla JS
+
+```javascript
+// instantiate the plugin
+var chart = new EasyPieChart(element, options);
+// update
+chart.update(40);
+// disable animation
+chart.disableAnimation();
+// enable animation
+chart.enableAnimation();
+```
+
+###### Using a gradient
+
+```javascript
+new EasyPieChart(element, {
+  barColor: function(percent) {
+    var ctx = this.renderer.ctx();
+    var canvas = this.renderer.canvas();
+    var gradient = ctx.createLinearGradient(0,0,canvas.width,0);
+        gradient.addColorStop(0, "#ffe57e");
+        gradient.addColorStop(1, "#de5900");
+    return gradient;
+  }
+});
+```
+
+#### AngularJS
+
+For a value binding you need to add the `percent` attribute and bind it to your controller.
+
+#### RequireJS
+
+When using [RequireJS](http://requirejs.org) you can define your own name. Examples can be found in the `demo/requirejs.html`.
+
+
+
+## Browser Support
+Native support
+
+* Chrome
+* Safari
+* FireFox
+* Opera
+* Internet Explorer 9+
+
+Support for Internet Explorer 7 and 8 with [excanvas](https://code.google.com/p/explorercanvas/wiki/Instructions) polyfill.
+
+
+
+## Test
+To run the test just use the karma adapter of grunt: `grunt test`
+
+
+
+## Credits
+Thanks to [Rafal Bromirski](http://www.paranoida.com/) for designing [this dribble shot](http://drbl.in/ezuc) which inspired me building this plugin.
+
+
+
+## Copyright
+Copyright (c) 2014 Robert Fleischmann, contributors. Released under the MIT, GPL licenses

+ 19 - 0
app/Resources/public/assets/jquery.easy-pie-chart/bower.json

@@ -0,0 +1,19 @@
+{
+  "name": "jquery.easy-pie-chart",
+  "version": "2.1.6",
+  "main": [
+    "dist/jquery.easypiechart.js"
+  ],
+  "ignore": [
+    "demo",
+    ".editorconfig"
+  ],
+  "dependencies": {
+    "jquery": ">=1.9.0",
+    "requirejs": "~2.1.10"
+  },
+  "devDependencies": {
+    "angular": "~1.2.9",
+    "angular-mocks": "~1.2.9"
+  }
+}

+ 80 - 0
app/Resources/public/assets/jquery.easy-pie-chart/changelog.md

@@ -0,0 +1,80 @@
+# Changlog
+
+## Version 2.1.5 - Feb 28, 2014
+* Fixed build error for minified vanilla version
+
+## Version 2.1.4 - Feb 1, 2014
+* Various updates and pull requests
+
+## Version 2.1.3 - Dec 1, 2013
+* Allow negative percent values with a reversed pie chart
+
+## Version 2.1.2 - Dec 1, 2013
+* Allow override of default options with data attributes in JQuery plugin
+
+## Version 2.1.1 - Nov 19, 2013
+* Fixed AMD support for jQuery version
+
+## Version 2.1.0 - Oct 28, 2013
+* Added UMD (Universal Module Definition) wrapper for AMD and requireJS support
+* Angular module: Move options into single attribute and provide it as JSON
+* Allow decimal numbers for percent values
+
+## Version 2.0.5 – Oct 12, 2013
+* (Angular) Fixed timer bug
+
+## Version 2.0.4 - Oct 10, 2013
+* Use the internal timing function of angular
+* Added the ability to create two instances of the chart on one main scope
+* Removed unnecessary stuff from the angular example to provide the minimal setup
+* Added more conventional way to create controller in angular
+
+## Version 2.0.3 - Sep 29, 2013
+* Fixed render bug on retina displays
+* Auto detect and load renderer (in preparation of a svg renderer)
+
+## Version 2.0.2 - Sep 26, 2013
+* Improved render performance by approx. 300%
+
+## Version 2.0.1 - Sep 22, 2013
+* Support for Internet Explorer 7 and 8 with excanvas
+
+## Version 2.0.0 - Sep 22, 2013
+* Added vanilla JS version
+* Added angular directive
+* Dropped coffeescript version
+* Dropped support for delayed animations
+* Moved canvas render methods in own module
+
+## Version 1.2.5 - Aug 05, 2013
+* Added default option value for delay
+
+## Version 1.2.4 - Aug 05, 2013
+* bug fix for incomplete animations
+* support for delayed animations
+
+## Version 1.2.3 - Jul 17, 2013
+* Date.now fix for IE < IE9
+
+## Version 1.2.2 - Jul 15, 2013
+* Add `currentValue` and `to` to the onStop callback
+
+## Version 1.2.1 - Jun 19, 2013
+* Allow overriding of options with HTML data attributes where provided
+
+## Version 1.2.0 - Jun 19, 2013
+* Added `rotate` option to rotate the complete chart
+
+## Version 1.1.0 - Jun 10, 2013
+* Added missing `onStop` method
+* cast `percent` to float to avoid breaking chart if a string is passed to the update method
+
+## Version 1.0.2 - Jun 07, 2013
+* Use requestAnimationFrame for smooth animations
+* Added `onStep` option to get the current value during animations
+
+## Version 1.0.1 - Feb 07, 2013
+* Added retina support
+
+## Version 1.0.0 - Aug 02, 2012
+* Initial version

+ 397 - 0
app/Resources/public/assets/jquery.easy-pie-chart/dist/angular.easypiechart.js

@@ -0,0 +1,397 @@
+/**!
+ * easyPieChart
+ * Lightweight plugin to render simple, animated and retina optimized pie charts
+ *
+ * @license 
+ * @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
+ * @version 2.1.6
+ **/
+
+(function(root, factory) {
+    if(typeof exports === 'object') {
+        module.exports = factory(require('angular'));
+    }
+    else if(typeof define === 'function' && define.amd) {
+        define(['angular'], factory);
+    }
+    else {
+        factory(root.angular);
+    }
+}(this, function(angular) {
+
+(function (angular) {
+
+	'use strict';
+
+	return angular.module('easypiechart', [])
+
+		.directive('easypiechart', [function() {
+			return {
+				restrict: 'A',
+				require: '?ngModel',
+				scope: {
+					percent: '=',
+					options: '='
+				},
+				link: function (scope, element, attrs) {
+
+					scope.percent = scope.percent || 0;
+
+					/**
+					 * default easy pie chart options
+					 * @type {Object}
+					 */
+					var options = {
+						barColor: '#ef1e25',
+						trackColor: '#f9f9f9',
+						scaleColor: '#dfe0e0',
+						scaleLength: 5,
+						lineCap: 'round',
+						lineWidth: 3,
+						size: 110,
+						rotate: 0,
+						animate: {
+							duration: 1000,
+							enabled: true
+						}
+					};
+					scope.options = angular.extend(options, scope.options);
+
+					var pieChart = new EasyPieChart(element[0], options);
+
+					scope.$watch('percent', function(newVal, oldVal) {
+						pieChart.update(newVal);
+					});
+				}
+			};
+		}]);
+
+})(angular);
+/**
+ * Renderer to render the chart on a canvas object
+ * @param {DOMElement} el      DOM element to host the canvas (root of the plugin)
+ * @param {object}     options options object of the plugin
+ */
+var CanvasRenderer = function(el, options) {
+	var cachedBackground;
+	var canvas = document.createElement('canvas');
+
+	el.appendChild(canvas);
+
+	if (typeof(G_vmlCanvasManager) !== 'undefined') {
+		G_vmlCanvasManager.initElement(canvas);
+	}
+
+	var ctx = canvas.getContext('2d');
+
+	canvas.width = canvas.height = options.size;
+
+	// canvas on retina devices
+	var scaleBy = 1;
+	if (window.devicePixelRatio > 1) {
+		scaleBy = window.devicePixelRatio;
+		canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
+		canvas.width = canvas.height = options.size * scaleBy;
+		ctx.scale(scaleBy, scaleBy);
+	}
+
+	// move 0,0 coordinates to the center
+	ctx.translate(options.size / 2, options.size / 2);
+
+	// rotate canvas -90deg
+	ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
+
+	var radius = (options.size - options.lineWidth) / 2;
+	if (options.scaleColor && options.scaleLength) {
+		radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
+	}
+
+	// IE polyfill for Date
+	Date.now = Date.now || function() {
+		return +(new Date());
+	};
+
+	/**
+	 * Draw a circle around the center of the canvas
+	 * @param {strong} color     Valid CSS color string
+	 * @param {number} lineWidth Width of the line in px
+	 * @param {number} percent   Percentage to draw (float between -1 and 1)
+	 */
+	var drawCircle = function(color, lineWidth, percent) {
+		percent = Math.min(Math.max(-1, percent || 0), 1);
+		var isNegative = percent <= 0 ? true : false;
+
+		ctx.beginPath();
+		ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
+
+		ctx.strokeStyle = color;
+		ctx.lineWidth = lineWidth;
+
+		ctx.stroke();
+	};
+
+	/**
+	 * Draw the scale of the chart
+	 */
+	var drawScale = function() {
+		var offset;
+		var length;
+
+		ctx.lineWidth = 1;
+		ctx.fillStyle = options.scaleColor;
+
+		ctx.save();
+		for (var i = 24; i > 0; --i) {
+			if (i % 6 === 0) {
+				length = options.scaleLength;
+				offset = 0;
+			} else {
+				length = options.scaleLength * 0.6;
+				offset = options.scaleLength - length;
+			}
+			ctx.fillRect(-options.size/2 + offset, 0, length, 1);
+			ctx.rotate(Math.PI / 12);
+		}
+		ctx.restore();
+	};
+
+	/**
+	 * Request animation frame wrapper with polyfill
+	 * @return {function} Request animation frame method or timeout fallback
+	 */
+	var reqAnimationFrame = (function() {
+		return  window.requestAnimationFrame ||
+				window.webkitRequestAnimationFrame ||
+				window.mozRequestAnimationFrame ||
+				function(callback) {
+					window.setTimeout(callback, 1000 / 60);
+				};
+	}());
+
+	/**
+	 * Draw the background of the plugin including the scale and the track
+	 */
+	var drawBackground = function() {
+		if(options.scaleColor) drawScale();
+		if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
+	};
+
+  /**
+    * Canvas accessor
+   */
+  this.getCanvas = function() {
+    return canvas;
+  };
+
+  /**
+    * Canvas 2D context 'ctx' accessor
+   */
+  this.getCtx = function() {
+    return ctx;
+  };
+
+	/**
+	 * Clear the complete canvas
+	 */
+	this.clear = function() {
+		ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
+	};
+
+	/**
+	 * Draw the complete chart
+	 * @param {number} percent Percent shown by the chart between -100 and 100
+	 */
+	this.draw = function(percent) {
+		// do we need to render a background
+		if (!!options.scaleColor || !!options.trackColor) {
+			// getImageData and putImageData are supported
+			if (ctx.getImageData && ctx.putImageData) {
+				if (!cachedBackground) {
+					drawBackground();
+					cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
+				} else {
+					ctx.putImageData(cachedBackground, 0, 0);
+				}
+			} else {
+				this.clear();
+				drawBackground();
+			}
+		} else {
+			this.clear();
+		}
+
+		ctx.lineCap = options.lineCap;
+
+		// if barcolor is a function execute it and pass the percent as a value
+		var color;
+		if (typeof(options.barColor) === 'function') {
+			color = options.barColor(percent);
+		} else {
+			color = options.barColor;
+		}
+
+		// draw bar
+		drawCircle(color, options.lineWidth, percent / 100);
+	}.bind(this);
+
+	/**
+	 * Animate from some percent to some other percentage
+	 * @param {number} from Starting percentage
+	 * @param {number} to   Final percentage
+	 */
+	this.animate = function(from, to) {
+		var startTime = Date.now();
+		options.onStart(from, to);
+		var animation = function() {
+			var process = Math.min(Date.now() - startTime, options.animate.duration);
+			var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
+			this.draw(currentValue);
+			options.onStep(from, to, currentValue);
+			if (process >= options.animate.duration) {
+				options.onStop(from, to);
+			} else {
+				reqAnimationFrame(animation);
+			}
+		}.bind(this);
+
+		reqAnimationFrame(animation);
+	}.bind(this);
+};
+
+var EasyPieChart = function(el, opts) {
+	var defaultOptions = {
+		barColor: '#ef1e25',
+		trackColor: '#f9f9f9',
+		scaleColor: '#dfe0e0',
+		scaleLength: 5,
+		lineCap: 'round',
+		lineWidth: 3,
+		trackWidth: undefined,
+		size: 110,
+		rotate: 0,
+		animate: {
+			duration: 1000,
+			enabled: true
+		},
+		easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
+			t = t / (d/2);
+			if (t < 1) {
+				return c / 2 * t * t + b;
+			}
+			return -c/2 * ((--t)*(t-2) - 1) + b;
+		},
+		onStart: function(from, to) {
+			return;
+		},
+		onStep: function(from, to, currentValue) {
+			return;
+		},
+		onStop: function(from, to) {
+			return;
+		}
+	};
+
+	// detect present renderer
+	if (typeof(CanvasRenderer) !== 'undefined') {
+		defaultOptions.renderer = CanvasRenderer;
+	} else if (typeof(SVGRenderer) !== 'undefined') {
+		defaultOptions.renderer = SVGRenderer;
+	} else {
+		throw new Error('Please load either the SVG- or the CanvasRenderer');
+	}
+
+	var options = {};
+	var currentValue = 0;
+
+	/**
+	 * Initialize the plugin by creating the options object and initialize rendering
+	 */
+	var init = function() {
+		this.el = el;
+		this.options = options;
+
+		// merge user options into default options
+		for (var i in defaultOptions) {
+			if (defaultOptions.hasOwnProperty(i)) {
+				options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
+				if (typeof(options[i]) === 'function') {
+					options[i] = options[i].bind(this);
+				}
+			}
+		}
+
+		// check for jQuery easing
+		if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
+			options.easing = jQuery.easing[options.easing];
+		} else {
+			options.easing = defaultOptions.easing;
+		}
+
+		// process earlier animate option to avoid bc breaks
+		if (typeof(options.animate) === 'number') {
+			options.animate = {
+				duration: options.animate,
+				enabled: true
+			};
+		}
+
+		if (typeof(options.animate) === 'boolean' && !options.animate) {
+			options.animate = {
+				duration: 1000,
+				enabled: options.animate
+			};
+		}
+
+		// create renderer
+		this.renderer = new options.renderer(el, options);
+
+		// initial draw
+		this.renderer.draw(currentValue);
+
+		// initial update
+		if (el.dataset && el.dataset.percent) {
+			this.update(parseFloat(el.dataset.percent));
+		} else if (el.getAttribute && el.getAttribute('data-percent')) {
+			this.update(parseFloat(el.getAttribute('data-percent')));
+		}
+	}.bind(this);
+
+	/**
+	 * Update the value of the chart
+	 * @param  {number} newValue Number between 0 and 100
+	 * @return {object}          Instance of the plugin for method chaining
+	 */
+	this.update = function(newValue) {
+		newValue = parseFloat(newValue);
+		if (options.animate.enabled) {
+			this.renderer.animate(currentValue, newValue);
+		} else {
+			this.renderer.draw(newValue);
+		}
+		currentValue = newValue;
+		return this;
+	}.bind(this);
+
+	/**
+	 * Disable animation
+	 * @return {object} Instance of the plugin for method chaining
+	 */
+	this.disableAnimation = function() {
+		options.animate.enabled = false;
+		return this;
+	};
+
+	/**
+	 * Enable animation
+	 * @return {object} Instance of the plugin for method chaining
+	 */
+	this.enableAnimation = function() {
+		options.animate.enabled = true;
+		return this;
+	};
+
+	init();
+};
+
+
+}));

File diff suppressed because it is too large
+ 8 - 0
app/Resources/public/assets/jquery.easy-pie-chart/dist/angular.easypiechart.min.js


+ 351 - 0
app/Resources/public/assets/jquery.easy-pie-chart/dist/easypiechart.js

@@ -0,0 +1,351 @@
+/**!
+ * easyPieChart
+ * Lightweight plugin to render simple, animated and retina optimized pie charts
+ *
+ * @license 
+ * @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
+ * @version 2.1.6
+ **/
+
+(function(root, factory) {
+    if(typeof exports === 'object') {
+        module.exports = factory();
+    }
+    else if(typeof define === 'function' && define.amd) {
+        define([], factory);
+    }
+    else {
+        root['EasyPieChart'] = factory();
+    }
+}(this, function() {
+
+/**
+ * Renderer to render the chart on a canvas object
+ * @param {DOMElement} el      DOM element to host the canvas (root of the plugin)
+ * @param {object}     options options object of the plugin
+ */
+var CanvasRenderer = function(el, options) {
+	var cachedBackground;
+	var canvas = document.createElement('canvas');
+
+	el.appendChild(canvas);
+
+	if (typeof(G_vmlCanvasManager) !== 'undefined') {
+		G_vmlCanvasManager.initElement(canvas);
+	}
+
+	var ctx = canvas.getContext('2d');
+
+	canvas.width = canvas.height = options.size;
+
+	// canvas on retina devices
+	var scaleBy = 1;
+	if (window.devicePixelRatio > 1) {
+		scaleBy = window.devicePixelRatio;
+		canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
+		canvas.width = canvas.height = options.size * scaleBy;
+		ctx.scale(scaleBy, scaleBy);
+	}
+
+	// move 0,0 coordinates to the center
+	ctx.translate(options.size / 2, options.size / 2);
+
+	// rotate canvas -90deg
+	ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
+
+	var radius = (options.size - options.lineWidth) / 2;
+	if (options.scaleColor && options.scaleLength) {
+		radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
+	}
+
+	// IE polyfill for Date
+	Date.now = Date.now || function() {
+		return +(new Date());
+	};
+
+	/**
+	 * Draw a circle around the center of the canvas
+	 * @param {strong} color     Valid CSS color string
+	 * @param {number} lineWidth Width of the line in px
+	 * @param {number} percent   Percentage to draw (float between -1 and 1)
+	 */
+	var drawCircle = function(color, lineWidth, percent) {
+		percent = Math.min(Math.max(-1, percent || 0), 1);
+		var isNegative = percent <= 0 ? true : false;
+
+		ctx.beginPath();
+		ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
+
+		ctx.strokeStyle = color;
+		ctx.lineWidth = lineWidth;
+
+		ctx.stroke();
+	};
+
+	/**
+	 * Draw the scale of the chart
+	 */
+	var drawScale = function() {
+		var offset;
+		var length;
+
+		ctx.lineWidth = 1;
+		ctx.fillStyle = options.scaleColor;
+
+		ctx.save();
+		for (var i = 24; i > 0; --i) {
+			if (i % 6 === 0) {
+				length = options.scaleLength;
+				offset = 0;
+			} else {
+				length = options.scaleLength * 0.6;
+				offset = options.scaleLength - length;
+			}
+			ctx.fillRect(-options.size/2 + offset, 0, length, 1);
+			ctx.rotate(Math.PI / 12);
+		}
+		ctx.restore();
+	};
+
+	/**
+	 * Request animation frame wrapper with polyfill
+	 * @return {function} Request animation frame method or timeout fallback
+	 */
+	var reqAnimationFrame = (function() {
+		return  window.requestAnimationFrame ||
+				window.webkitRequestAnimationFrame ||
+				window.mozRequestAnimationFrame ||
+				function(callback) {
+					window.setTimeout(callback, 1000 / 60);
+				};
+	}());
+
+	/**
+	 * Draw the background of the plugin including the scale and the track
+	 */
+	var drawBackground = function() {
+		if(options.scaleColor) drawScale();
+		if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
+	};
+
+  /**
+    * Canvas accessor
+   */
+  this.getCanvas = function() {
+    return canvas;
+  };
+
+  /**
+    * Canvas 2D context 'ctx' accessor
+   */
+  this.getCtx = function() {
+    return ctx;
+  };
+
+	/**
+	 * Clear the complete canvas
+	 */
+	this.clear = function() {
+		ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
+	};
+
+	/**
+	 * Draw the complete chart
+	 * @param {number} percent Percent shown by the chart between -100 and 100
+	 */
+	this.draw = function(percent) {
+		// do we need to render a background
+		if (!!options.scaleColor || !!options.trackColor) {
+			// getImageData and putImageData are supported
+			if (ctx.getImageData && ctx.putImageData) {
+				if (!cachedBackground) {
+					drawBackground();
+					cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
+				} else {
+					ctx.putImageData(cachedBackground, 0, 0);
+				}
+			} else {
+				this.clear();
+				drawBackground();
+			}
+		} else {
+			this.clear();
+		}
+
+		ctx.lineCap = options.lineCap;
+
+		// if barcolor is a function execute it and pass the percent as a value
+		var color;
+		if (typeof(options.barColor) === 'function') {
+			color = options.barColor(percent);
+		} else {
+			color = options.barColor;
+		}
+
+		// draw bar
+		drawCircle(color, options.lineWidth, percent / 100);
+	}.bind(this);
+
+	/**
+	 * Animate from some percent to some other percentage
+	 * @param {number} from Starting percentage
+	 * @param {number} to   Final percentage
+	 */
+	this.animate = function(from, to) {
+		var startTime = Date.now();
+		options.onStart(from, to);
+		var animation = function() {
+			var process = Math.min(Date.now() - startTime, options.animate.duration);
+			var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
+			this.draw(currentValue);
+			options.onStep(from, to, currentValue);
+			if (process >= options.animate.duration) {
+				options.onStop(from, to);
+			} else {
+				reqAnimationFrame(animation);
+			}
+		}.bind(this);
+
+		reqAnimationFrame(animation);
+	}.bind(this);
+};
+
+var EasyPieChart = function(el, opts) {
+	var defaultOptions = {
+		barColor: '#ef1e25',
+		trackColor: '#f9f9f9',
+		scaleColor: '#dfe0e0',
+		scaleLength: 5,
+		lineCap: 'round',
+		lineWidth: 3,
+		trackWidth: undefined,
+		size: 110,
+		rotate: 0,
+		animate: {
+			duration: 1000,
+			enabled: true
+		},
+		easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
+			t = t / (d/2);
+			if (t < 1) {
+				return c / 2 * t * t + b;
+			}
+			return -c/2 * ((--t)*(t-2) - 1) + b;
+		},
+		onStart: function(from, to) {
+			return;
+		},
+		onStep: function(from, to, currentValue) {
+			return;
+		},
+		onStop: function(from, to) {
+			return;
+		}
+	};
+
+	// detect present renderer
+	if (typeof(CanvasRenderer) !== 'undefined') {
+		defaultOptions.renderer = CanvasRenderer;
+	} else if (typeof(SVGRenderer) !== 'undefined') {
+		defaultOptions.renderer = SVGRenderer;
+	} else {
+		throw new Error('Please load either the SVG- or the CanvasRenderer');
+	}
+
+	var options = {};
+	var currentValue = 0;
+
+	/**
+	 * Initialize the plugin by creating the options object and initialize rendering
+	 */
+	var init = function() {
+		this.el = el;
+		this.options = options;
+
+		// merge user options into default options
+		for (var i in defaultOptions) {
+			if (defaultOptions.hasOwnProperty(i)) {
+				options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
+				if (typeof(options[i]) === 'function') {
+					options[i] = options[i].bind(this);
+				}
+			}
+		}
+
+		// check for jQuery easing
+		if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
+			options.easing = jQuery.easing[options.easing];
+		} else {
+			options.easing = defaultOptions.easing;
+		}
+
+		// process earlier animate option to avoid bc breaks
+		if (typeof(options.animate) === 'number') {
+			options.animate = {
+				duration: options.animate,
+				enabled: true
+			};
+		}
+
+		if (typeof(options.animate) === 'boolean' && !options.animate) {
+			options.animate = {
+				duration: 1000,
+				enabled: options.animate
+			};
+		}
+
+		// create renderer
+		this.renderer = new options.renderer(el, options);
+
+		// initial draw
+		this.renderer.draw(currentValue);
+
+		// initial update
+		if (el.dataset && el.dataset.percent) {
+			this.update(parseFloat(el.dataset.percent));
+		} else if (el.getAttribute && el.getAttribute('data-percent')) {
+			this.update(parseFloat(el.getAttribute('data-percent')));
+		}
+	}.bind(this);
+
+	/**
+	 * Update the value of the chart
+	 * @param  {number} newValue Number between 0 and 100
+	 * @return {object}          Instance of the plugin for method chaining
+	 */
+	this.update = function(newValue) {
+		newValue = parseFloat(newValue);
+		if (options.animate.enabled) {
+			this.renderer.animate(currentValue, newValue);
+		} else {
+			this.renderer.draw(newValue);
+		}
+		currentValue = newValue;
+		return this;
+	}.bind(this);
+
+	/**
+	 * Disable animation
+	 * @return {object} Instance of the plugin for method chaining
+	 */
+	this.disableAnimation = function() {
+		options.animate.enabled = false;
+		return this;
+	};
+
+	/**
+	 * Enable animation
+	 * @return {object} Instance of the plugin for method chaining
+	 */
+	this.enableAnimation = function() {
+		options.animate.enabled = true;
+		return this;
+	};
+
+	init();
+};
+
+
+return EasyPieChart;
+
+}));

File diff suppressed because it is too large
+ 8 - 0
app/Resources/public/assets/jquery.easy-pie-chart/dist/easypiechart.min.js


+ 360 - 0
app/Resources/public/assets/jquery.easy-pie-chart/dist/jquery.easypiechart.js

@@ -0,0 +1,360 @@
+/**!
+ * easyPieChart
+ * Lightweight plugin to render simple, animated and retina optimized pie charts
+ *
+ * @license 
+ * @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
+ * @version 2.1.6
+ **/
+
+(function(root, factory) {
+    if(typeof exports === 'object') {
+        module.exports = factory(require('jquery'));
+    }
+    else if(typeof define === 'function' && define.amd) {
+        define(['jquery'], factory);
+    }
+    else {
+        factory(root.jQuery);
+    }
+}(this, function($) {
+
+/**
+ * Renderer to render the chart on a canvas object
+ * @param {DOMElement} el      DOM element to host the canvas (root of the plugin)
+ * @param {object}     options options object of the plugin
+ */
+var CanvasRenderer = function(el, options) {
+	var cachedBackground;
+	var canvas = document.createElement('canvas');
+
+	el.appendChild(canvas);
+
+	if (typeof(G_vmlCanvasManager) !== 'undefined') {
+		G_vmlCanvasManager.initElement(canvas);
+	}
+
+	var ctx = canvas.getContext('2d');
+
+	canvas.width = canvas.height = options.size;
+
+	// canvas on retina devices
+	var scaleBy = 1;
+	if (window.devicePixelRatio > 1) {
+		scaleBy = window.devicePixelRatio;
+		canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
+		canvas.width = canvas.height = options.size * scaleBy;
+		ctx.scale(scaleBy, scaleBy);
+	}
+
+	// move 0,0 coordinates to the center
+	ctx.translate(options.size / 2, options.size / 2);
+
+	// rotate canvas -90deg
+	ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
+
+	var radius = (options.size - options.lineWidth) / 2;
+	if (options.scaleColor && options.scaleLength) {
+		radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
+	}
+
+	// IE polyfill for Date
+	Date.now = Date.now || function() {
+		return +(new Date());
+	};
+
+	/**
+	 * Draw a circle around the center of the canvas
+	 * @param {strong} color     Valid CSS color string
+	 * @param {number} lineWidth Width of the line in px
+	 * @param {number} percent   Percentage to draw (float between -1 and 1)
+	 */
+	var drawCircle = function(color, lineWidth, percent) {
+		percent = Math.min(Math.max(-1, percent || 0), 1);
+		var isNegative = percent <= 0 ? true : false;
+
+		ctx.beginPath();
+		ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
+
+		ctx.strokeStyle = color;
+		ctx.lineWidth = lineWidth;
+
+		ctx.stroke();
+	};
+
+	/**
+	 * Draw the scale of the chart
+	 */
+	var drawScale = function() {
+		var offset;
+		var length;
+
+		ctx.lineWidth = 1;
+		ctx.fillStyle = options.scaleColor;
+
+		ctx.save();
+		for (var i = 24; i > 0; --i) {
+			if (i % 6 === 0) {
+				length = options.scaleLength;
+				offset = 0;
+			} else {
+				length = options.scaleLength * 0.6;
+				offset = options.scaleLength - length;
+			}
+			ctx.fillRect(-options.size/2 + offset, 0, length, 1);
+			ctx.rotate(Math.PI / 12);
+		}
+		ctx.restore();
+	};
+
+	/**
+	 * Request animation frame wrapper with polyfill
+	 * @return {function} Request animation frame method or timeout fallback
+	 */
+	var reqAnimationFrame = (function() {
+		return  window.requestAnimationFrame ||
+				window.webkitRequestAnimationFrame ||
+				window.mozRequestAnimationFrame ||
+				function(callback) {
+					window.setTimeout(callback, 1000 / 60);
+				};
+	}());
+
+	/**
+	 * Draw the background of the plugin including the scale and the track
+	 */
+	var drawBackground = function() {
+		if(options.scaleColor) drawScale();
+		if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
+	};
+
+  /**
+    * Canvas accessor
+   */
+  this.getCanvas = function() {
+    return canvas;
+  };
+
+  /**
+    * Canvas 2D context 'ctx' accessor
+   */
+  this.getCtx = function() {
+    return ctx;
+  };
+
+	/**
+	 * Clear the complete canvas
+	 */
+	this.clear = function() {
+		ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
+	};
+
+	/**
+	 * Draw the complete chart
+	 * @param {number} percent Percent shown by the chart between -100 and 100
+	 */
+	this.draw = function(percent) {
+		// do we need to render a background
+		if (!!options.scaleColor || !!options.trackColor) {
+			// getImageData and putImageData are supported
+			if (ctx.getImageData && ctx.putImageData) {
+				if (!cachedBackground) {
+					drawBackground();
+					cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
+				} else {
+					ctx.putImageData(cachedBackground, 0, 0);
+				}
+			} else {
+				this.clear();
+				drawBackground();
+			}
+		} else {
+			this.clear();
+		}
+
+		ctx.lineCap = options.lineCap;
+
+		// if barcolor is a function execute it and pass the percent as a value
+		var color;
+		if (typeof(options.barColor) === 'function') {
+			color = options.barColor(percent);
+		} else {
+			color = options.barColor;
+		}
+
+		// draw bar
+		drawCircle(color, options.lineWidth, percent / 100);
+	}.bind(this);
+
+	/**
+	 * Animate from some percent to some other percentage
+	 * @param {number} from Starting percentage
+	 * @param {number} to   Final percentage
+	 */
+	this.animate = function(from, to) {
+		var startTime = Date.now();
+		options.onStart(from, to);
+		var animation = function() {
+			var process = Math.min(Date.now() - startTime, options.animate.duration);
+			var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
+			this.draw(currentValue);
+			options.onStep(from, to, currentValue);
+			if (process >= options.animate.duration) {
+				options.onStop(from, to);
+			} else {
+				reqAnimationFrame(animation);
+			}
+		}.bind(this);
+
+		reqAnimationFrame(animation);
+	}.bind(this);
+};
+
+var EasyPieChart = function(el, opts) {
+	var defaultOptions = {
+		barColor: '#ef1e25',
+		trackColor: '#f9f9f9',
+		scaleColor: '#dfe0e0',
+		scaleLength: 5,
+		lineCap: 'round',
+		lineWidth: 3,
+		trackWidth: undefined,
+		size: 110,
+		rotate: 0,
+		animate: {
+			duration: 1000,
+			enabled: true
+		},
+		easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
+			t = t / (d/2);
+			if (t < 1) {
+				return c / 2 * t * t + b;
+			}
+			return -c/2 * ((--t)*(t-2) - 1) + b;
+		},
+		onStart: function(from, to) {
+			return;
+		},
+		onStep: function(from, to, currentValue) {
+			return;
+		},
+		onStop: function(from, to) {
+			return;
+		}
+	};
+
+	// detect present renderer
+	if (typeof(CanvasRenderer) !== 'undefined') {
+		defaultOptions.renderer = CanvasRenderer;
+	} else if (typeof(SVGRenderer) !== 'undefined') {
+		defaultOptions.renderer = SVGRenderer;
+	} else {
+		throw new Error('Please load either the SVG- or the CanvasRenderer');
+	}
+
+	var options = {};
+	var currentValue = 0;
+
+	/**
+	 * Initialize the plugin by creating the options object and initialize rendering
+	 */
+	var init = function() {
+		this.el = el;
+		this.options = options;
+
+		// merge user options into default options
+		for (var i in defaultOptions) {
+			if (defaultOptions.hasOwnProperty(i)) {
+				options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
+				if (typeof(options[i]) === 'function') {
+					options[i] = options[i].bind(this);
+				}
+			}
+		}
+
+		// check for jQuery easing
+		if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
+			options.easing = jQuery.easing[options.easing];
+		} else {
+			options.easing = defaultOptions.easing;
+		}
+
+		// process earlier animate option to avoid bc breaks
+		if (typeof(options.animate) === 'number') {
+			options.animate = {
+				duration: options.animate,
+				enabled: true
+			};
+		}
+
+		if (typeof(options.animate) === 'boolean' && !options.animate) {
+			options.animate = {
+				duration: 1000,
+				enabled: options.animate
+			};
+		}
+
+		// create renderer
+		this.renderer = new options.renderer(el, options);
+
+		// initial draw
+		this.renderer.draw(currentValue);
+
+		// initial update
+		if (el.dataset && el.dataset.percent) {
+			this.update(parseFloat(el.dataset.percent));
+		} else if (el.getAttribute && el.getAttribute('data-percent')) {
+			this.update(parseFloat(el.getAttribute('data-percent')));
+		}
+	}.bind(this);
+
+	/**
+	 * Update the value of the chart
+	 * @param  {number} newValue Number between 0 and 100
+	 * @return {object}          Instance of the plugin for method chaining
+	 */
+	this.update = function(newValue) {
+		newValue = parseFloat(newValue);
+		if (options.animate.enabled) {
+			this.renderer.animate(currentValue, newValue);
+		} else {
+			this.renderer.draw(newValue);
+		}
+		currentValue = newValue;
+		return this;
+	}.bind(this);
+
+	/**
+	 * Disable animation
+	 * @return {object} Instance of the plugin for method chaining
+	 */
+	this.disableAnimation = function() {
+		options.animate.enabled = false;
+		return this;
+	};
+
+	/**
+	 * Enable animation
+	 * @return {object} Instance of the plugin for method chaining
+	 */
+	this.enableAnimation = function() {
+		options.animate.enabled = true;
+		return this;
+	};
+
+	init();
+};
+
+$.fn.easyPieChart = function(options) {
+	return this.each(function() {
+		var instanceOptions;
+
+		if (!$.data(this, 'easyPieChart')) {
+			instanceOptions = $.extend({}, options, $(this).data());
+			$.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions));
+		}
+	});
+};
+
+
+}));

File diff suppressed because it is too large
+ 8 - 0
app/Resources/public/assets/jquery.easy-pie-chart/dist/jquery.easypiechart.min.js


+ 32 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/README.tmpl.md

@@ -0,0 +1,32 @@
+# {%= name %}
+
+> {%= description %}
+
+{%= _.doc('bagdes.md') %}
+
+## Features
+{%= _.doc("features.md") %}
+
+## Get started
+{%= _.doc("get-started.md") %}
+
+## Options
+{%= _.doc("options.md") %}
+
+## Callbacks
+{%= _.doc("callbacks.md") %}
+
+## Plugin api
+{%= _.doc("plugin-api.md") %}
+
+## Browser Support
+{%= _.doc("browser-support.md") %}
+
+## Test
+{%= _.doc("test.md") %}
+
+## Credits
+{%= _.doc("credits.md") %}
+
+## Copyright
+{%= copyright %} {%= license %}

+ 4 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/bagdes.md

@@ -0,0 +1,4 @@
+![Version](http://img.shields.io/version/{%= version %}.png?color=green)
+[![Build Status](https://travis-ci.org/rendro/easy-pie-chart.png)](https://travis-ci.org/rendro/easy-pie-chart)
+[![Dependencies Status](https://david-dm.org/rendro/easy-pie-chart/dev-status.png)](https://david-dm.org/rendro/easy-pie-chart)
+[![Analytics](https://ga-beacon.appspot.com/UA-46840672-1/easy-pie-chart/readme)](https://github.com/igrigorik/ga-beacon)

+ 9 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/browser-support.md

@@ -0,0 +1,9 @@
+Native support
+
+* Chrome
+* Safari
+* FireFox
+* Opera
+* Internet Explorer 9+
+
+Support for Internet Explorer 7 and 8 with [excanvas](https://code.google.com/p/explorercanvas/wiki/Instructions) polyfill.

+ 20 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/callbacks.md

@@ -0,0 +1,20 @@
+All callbacks will only be called if `animate` is not `false`.
+
+<table>
+    <tr>
+        <th>Callback(params, ...)</th>
+        <th>Description</th>
+    </tr>
+    <tr>
+        <td><strong>onStart(from, to)</strong></td>
+        <td>Is called at the start of any animation.</td>
+    </tr>
+    <tr>
+        <td><strong>onStep(from, to, currentValue)</strong></td>
+        <td>Is called during animations providing the current value (the method is scoped to the context of th eplugin, so you can access the DOM element via <code>this.el</code>).</td>
+    </tr>
+    <tr>
+        <td><strong>onStop(from, to)</strong></td>
+        <td>Is called at the end of any animation.</td>
+    </tr>
+</table>

+ 1 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/credits.md

@@ -0,0 +1 @@
+Thanks to [Rafal Bromirski](http://www.paranoida.com/) for designing [this dribble shot](http://drbl.in/ezuc) which inspired me building this plugin.

+ 13 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/features.md

@@ -0,0 +1,13 @@
+[![](https://github.com/rendro/easy-pie-chart/raw/master/demo/img/easy-pie-chart.png)](http://drbl.in/ezuc)
+
+* highly customizable
+* very easy to implement
+* resolution independent (retina optimized)
+* uses `requestAnimationFrame` for smooth animations on modern devices and
+* works in all modern browsers, even in IE7+ with [excanvas](https://code.google.com/p/explorercanvas/wiki/Instructions)
+
+### framework support
+
+* Vanilla JS *(no dependencies)* (~872 bytes)
+* jQuery plugin (~921 bytes)
+* Angular Module (~983 bytes)

+ 68 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/get-started.md

@@ -0,0 +1,68 @@
+### Installation
+
+You can also use [bower](http://bower.io) to install the component:
+
+```
+$ bower install jquery.easy-pie-chart
+```
+
+### jQuery
+
+To use the easy pie chart plugin you need to load the current version of jQuery (> 1.6.4) and the source of the plugin.
+
+```html
+<div class="chart" data-percent="73" data-scale-color="#ffb400">73%</div>
+
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
+<script src="/path/to/jquery.easy-pie-chart.js"></script>
+<script>
+    $(function() {
+        $('.chart').easyPieChart({
+            //your options goes here
+        });
+    });
+</script>
+```
+
+### Vanilla JS
+
+If you don't want to use jQuery, implement the Vanilla JS version without any dependencies.
+
+```html
+<div class="chart" data-percent="73">73%</div>
+
+<script src="/path/to/easy-pie-chart.js"></script>
+<script>
+    var element = document.querySelector('.chart');
+    new EasyPieChart(element, {
+        // your options goes here
+    });
+</script>
+```
+
+### AngularJS
+
+```html
+<div ng-controller="chartCtrl">
+    <div easypiechart options="options" percent="percent"></div>
+</div>
+
+<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
+<script src="../dist/angular.easypiechart.min.js"></script>
+<script>
+    var app = angular.module('app', ['easypiechart']);
+    app.controller('chartCtrl', ['$scope', function ($scope) {
+        $scope.percent = 65;
+        $scope.options = {
+            animate:{
+                duration:0,
+                enabled:false
+            },
+            barColor:'#2C3E50',
+            scaleColor:false,
+            lineWidth:20,
+            lineCap:'circle'
+        };
+    }]);
+</script>
+```

+ 59 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/options.md

@@ -0,0 +1,59 @@
+You can pass these options to the initialize function to set a custom look and feel for the plugin.
+
+<table>
+    <tr>
+        <th>Property (Type)</th>
+        <th>Default</th>
+        <th>Description</th>
+    </tr>
+    <tr>
+        <td><strong>barColor</strong></td>
+        <td>#ef1e25</td>
+        <td>The color of the curcular bar. You can either pass a valid css color string, or a function that takes the current percentage as a value and returns a valid css color string.</td>
+    </tr>
+    <tr>
+        <td><strong>trackColor</strong></td>
+        <td>#f2f2f2</td>
+        <td>The color of the track, or false to disable rendering.</td>
+    </tr>
+    <tr>
+        <td><strong>scaleColor</strong></td>
+        <td>#dfe0e0</td>
+        <td>The color of the scale lines, false to disable rendering.</td>
+    </tr>
+    <tr>
+        <td><strong>scaleLength</strong></td>
+        <td>5</td>
+        <td>Length of the scale lines (reduces the radius of the chart).</td>
+    </tr>
+    <tr>
+        <td><strong>lineCap</strong></td>
+        <td>round</td>
+        <td>Defines how the ending of the bar line looks like. Possible values are: <code>butt</code>, <code>round</code> and <code>square</code>.</td>
+    </tr>
+    <tr>
+        <td><strong>lineWidth</strong></td>
+        <td>3</td>
+        <td>Width of the chart line in px.</td>
+    </tr>
+    <tr>
+        <td><strong>size</strong></td>
+        <td>110</td>
+        <td>Size of the pie chart in px. It will always be a square.</td>
+    </tr>
+        <tr>
+        <td><strong>rotate</strong></td>
+        <td>0</td>
+        <td>Rotation of the complete chart in degrees.</td>
+    </tr>
+    <tr>
+        <td><strong>animate</strong></td>
+        <td>object</td>
+        <td>Object with time in milliseconds and boolean for an animation of the bar growing (<code>{ duration: 1000, enabled: true }</code>), or false to deactivate animations.</td>
+    </tr>
+    <tr>
+        <td><strong>easing</strong></td>
+        <td>defaultEasing</td>
+        <td>Easing function or string with the name of a <a href="http://gsgd.co.uk/sandbox/jquery/easing/" target="_blank">jQuery easing function</a></td>
+    </tr>
+</table>

+ 52 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/plugin-api.md

@@ -0,0 +1,52 @@
+### jQuery
+
+```javascript
+$(function() {
+    // instantiate the plugin
+    ...
+    // update
+    $('.chart').data('easyPieChart').update(40);
+    ...
+    // disable animation
+    $('.chart').data('easyPieChart').disableAnimation();
+    ...
+    // enable animation
+    $('.chart').data('easyPieChart').enableAnimation();
+});
+```
+
+### Vanilla JS
+
+```javascript
+// instantiate the plugin
+var chart = new EasyPieChart(element, options);
+// update
+chart.update(40);
+// disable animation
+chart.disableAnimation();
+// enable animation
+chart.enableAnimation();
+```
+
+##### Using a gradient
+
+```javascript
+new EasyPieChart(element, {
+  barColor: function(percent) {
+    var ctx = this.renderer.ctx();
+    var canvas = this.renderer.canvas();
+    var gradient = ctx.createLinearGradient(0,0,canvas.width,0);
+        gradient.addColorStop(0, "#ffe57e");
+        gradient.addColorStop(1, "#de5900");
+    return gradient;
+  }
+});
+```
+
+### AngularJS
+
+For a value binding you need to add the `percent` attribute and bind it to your controller.
+
+### RequireJS
+
+When using [RequireJS](http://requirejs.org) you can define your own name. Examples can be found in the `demo/requirejs.html`.

+ 1 - 0
app/Resources/public/assets/jquery.easy-pie-chart/docs/test.md

@@ -0,0 +1 @@
+To run the test just use the karma adapter of grunt: `grunt test`

+ 53 - 0
app/Resources/public/assets/jquery.easy-pie-chart/karma.conf.coffee

@@ -0,0 +1,53 @@
+# Karma configuration
+# http://karma-runner.github.io/0.10/config/configuration-file.html
+module.exports = (config) ->
+  config.set
+
+    # base path, that will be used to resolve files and exclude
+    basePath: ''
+
+    # testing framework to use (jasmine/mocha/qunit/...)
+    frameworks: ['jasmine']
+
+    # list of files / patterns to load in the browser
+    files: [
+      'test/polyfills/bind.js'
+      'bower_components/jquery/dist/jquery.js'
+      'bower_components/angular/angular.js'
+      'bower_components/angular-mocks/angular-mocks.js'
+      'src/renderer/canvas.js'
+      'src/easypiechart.js'
+      'src/jquery.plugin.js'
+      'src/angular.directive.js'
+      'test/**/*.js'
+    ]
+
+    # list of files / patterns to exclude
+    exclude: []
+
+    # web server port
+    port: 8080
+
+    # level of logging
+    # possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
+    logLevel: config.LOG_INFO
+
+    # enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true
+
+    # reporters
+    reporters: ['progress', 'dots']
+
+    # Start these browsers, currently available:
+    # - Chrome
+    # - ChromeCanary
+    # - Firefox
+    # - Opera
+    # - Safari (only Mac)
+    # - PhantomJS
+    # - IE (only Windows)
+    browsers: ['Chrome']
+
+    # Continuous Integration mode
+    # if true, it capture browsers, run tests and exit
+    singleRun: false

+ 51 - 0
app/Resources/public/assets/jquery.easy-pie-chart/package.json

@@ -0,0 +1,51 @@
+{
+  "name": "easyPieChart",
+  "description": "Lightweight plugin to render simple, animated and retina optimized pie charts",
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "http://www.opensource.org/licenses/mit-license.php"
+    },
+    {
+      "type": "GPL",
+      "url": "http://www.opensource.org/licenses/gpl-license.php"
+    }
+  ],
+  "version": "2.1.6",
+  "author": {
+    "name": "Robert Fleischmann",
+    "email": "rendro87@gmail.com",
+    "url": "http://robert-fleischmann.de"
+  },
+  "scripts": {
+    "test": "grunt karma:ci"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/rendro/easy-pie-chart.git"
+  },
+  "devDependencies": {
+    "grunt": "~0.4.1",
+    "grunt-contrib-concat": "~0.4.0",
+    "grunt-banner": "~0.2.0",
+    "grunt-contrib-clean": "~0.5.0",
+    "grunt-contrib-uglify": "~0.4.0",
+    "grunt-contrib-watch": "~0.6.1",
+    "grunt-contrib-less": "~0.11.0",
+    "grunt-contrib-jshint": "~0.10.0",
+    "karma-script-launcher": "~0.1.0",
+    "karma-firefox-launcher": "~0.1.0",
+    "karma-chrome-launcher": "~0.1.0",
+    "karma-html2js-preprocessor": "~0.1.0",
+    "karma-jasmine": "~0.1.3",
+    "karma-requirejs": "~0.2.1",
+    "karma-coffee-preprocessor": "~0.2.1",
+    "karma-phantomjs-launcher": "~0.1.0",
+    "karma": "~0.12.14",
+    "grunt-karma": "~0.8.3",
+    "grunt-umd": "~1.7.3",
+    "requirejs": "~2.1.10",
+    "grunt-readme": "~0.4.5",
+    "load-grunt-tasks": "~0.4.0"
+  }
+}

+ 48 - 0
app/Resources/public/assets/jquery.easy-pie-chart/src/angular.directive.js

@@ -0,0 +1,48 @@
+(function (angular) {
+
+	'use strict';
+
+	return angular.module('easypiechart', [])
+
+		.directive('easypiechart', [function() {
+			return {
+				restrict: 'A',
+				require: '?ngModel',
+				scope: {
+					percent: '=',
+					options: '='
+				},
+				link: function (scope, element, attrs) {
+
+					scope.percent = scope.percent || 0;
+
+					/**
+					 * default easy pie chart options
+					 * @type {Object}
+					 */
+					var options = {
+						barColor: '#ef1e25',
+						trackColor: '#f9f9f9',
+						scaleColor: '#dfe0e0',
+						scaleLength: 5,
+						lineCap: 'round',
+						lineWidth: 3,
+						size: 110,
+						rotate: 0,
+						animate: {
+							duration: 1000,
+							enabled: true
+						}
+					};
+					scope.options = angular.extend(options, scope.options);
+
+					var pieChart = new EasyPieChart(element[0], options);
+
+					scope.$watch('percent', function(newVal, oldVal) {
+						pieChart.update(newVal);
+					});
+				}
+			};
+		}]);
+
+})(angular);

+ 134 - 0
app/Resources/public/assets/jquery.easy-pie-chart/src/easypiechart.js

@@ -0,0 +1,134 @@
+var EasyPieChart = function(el, opts) {
+	var defaultOptions = {
+		barColor: '#ef1e25',
+		trackColor: '#f9f9f9',
+		scaleColor: '#dfe0e0',
+		scaleLength: 5,
+		lineCap: 'round',
+		lineWidth: 3,
+		trackWidth: undefined,
+		size: 110,
+		rotate: 0,
+		animate: {
+			duration: 1000,
+			enabled: true
+		},
+		easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
+			t = t / (d/2);
+			if (t < 1) {
+				return c / 2 * t * t + b;
+			}
+			return -c/2 * ((--t)*(t-2) - 1) + b;
+		},
+		onStart: function(from, to) {
+			return;
+		},
+		onStep: function(from, to, currentValue) {
+			return;
+		},
+		onStop: function(from, to) {
+			return;
+		}
+	};
+
+	// detect present renderer
+	if (typeof(CanvasRenderer) !== 'undefined') {
+		defaultOptions.renderer = CanvasRenderer;
+	} else if (typeof(SVGRenderer) !== 'undefined') {
+		defaultOptions.renderer = SVGRenderer;
+	} else {
+		throw new Error('Please load either the SVG- or the CanvasRenderer');
+	}
+
+	var options = {};
+	var currentValue = 0;
+
+	/**
+	 * Initialize the plugin by creating the options object and initialize rendering
+	 */
+	var init = function() {
+		this.el = el;
+		this.options = options;
+
+		// merge user options into default options
+		for (var i in defaultOptions) {
+			if (defaultOptions.hasOwnProperty(i)) {
+				options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
+				if (typeof(options[i]) === 'function') {
+					options[i] = options[i].bind(this);
+				}
+			}
+		}
+
+		// check for jQuery easing
+		if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
+			options.easing = jQuery.easing[options.easing];
+		} else {
+			options.easing = defaultOptions.easing;
+		}
+
+		// process earlier animate option to avoid bc breaks
+		if (typeof(options.animate) === 'number') {
+			options.animate = {
+				duration: options.animate,
+				enabled: true
+			};
+		}
+
+		if (typeof(options.animate) === 'boolean' && !options.animate) {
+			options.animate = {
+				duration: 1000,
+				enabled: options.animate
+			};
+		}
+
+		// create renderer
+		this.renderer = new options.renderer(el, options);
+
+		// initial draw
+		this.renderer.draw(currentValue);
+
+		// initial update
+		if (el.dataset && el.dataset.percent) {
+			this.update(parseFloat(el.dataset.percent));
+		} else if (el.getAttribute && el.getAttribute('data-percent')) {
+			this.update(parseFloat(el.getAttribute('data-percent')));
+		}
+	}.bind(this);
+
+	/**
+	 * Update the value of the chart
+	 * @param  {number} newValue Number between 0 and 100
+	 * @return {object}          Instance of the plugin for method chaining
+	 */
+	this.update = function(newValue) {
+		newValue = parseFloat(newValue);
+		if (options.animate.enabled) {
+			this.renderer.animate(currentValue, newValue);
+		} else {
+			this.renderer.draw(newValue);
+		}
+		currentValue = newValue;
+		return this;
+	}.bind(this);
+
+	/**
+	 * Disable animation
+	 * @return {object} Instance of the plugin for method chaining
+	 */
+	this.disableAnimation = function() {
+		options.animate.enabled = false;
+		return this;
+	};
+
+	/**
+	 * Enable animation
+	 * @return {object} Instance of the plugin for method chaining
+	 */
+	this.enableAnimation = function() {
+		options.animate.enabled = true;
+		return this;
+	};
+
+	init();
+};

+ 10 - 0
app/Resources/public/assets/jquery.easy-pie-chart/src/jquery.plugin.js

@@ -0,0 +1,10 @@
+$.fn.easyPieChart = function(options) {
+	return this.each(function() {
+		var instanceOptions;
+
+		if (!$.data(this, 'easyPieChart')) {
+			instanceOptions = $.extend({}, options, $(this).data());
+			$.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions));
+		}
+	});
+};

+ 190 - 0
app/Resources/public/assets/jquery.easy-pie-chart/src/renderer/canvas.js

@@ -0,0 +1,190 @@
+/**
+ * Renderer to render the chart on a canvas object
+ * @param {DOMElement} el      DOM element to host the canvas (root of the plugin)
+ * @param {object}     options options object of the plugin
+ */
+var CanvasRenderer = function(el, options) {
+	var cachedBackground;
+	var canvas = document.createElement('canvas');
+
+	el.appendChild(canvas);
+
+	if (typeof(G_vmlCanvasManager) !== 'undefined') {
+		G_vmlCanvasManager.initElement(canvas);
+	}
+
+	var ctx = canvas.getContext('2d');
+
+	canvas.width = canvas.height = options.size;
+
+	// canvas on retina devices
+	var scaleBy = 1;
+	if (window.devicePixelRatio > 1) {
+		scaleBy = window.devicePixelRatio;
+		canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
+		canvas.width = canvas.height = options.size * scaleBy;
+		ctx.scale(scaleBy, scaleBy);
+	}
+
+	// move 0,0 coordinates to the center
+	ctx.translate(options.size / 2, options.size / 2);
+
+	// rotate canvas -90deg
+	ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
+
+	var radius = (options.size - options.lineWidth) / 2;
+	if (options.scaleColor && options.scaleLength) {
+		radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
+	}
+
+	// IE polyfill for Date
+	Date.now = Date.now || function() {
+		return +(new Date());
+	};
+
+	/**
+	 * Draw a circle around the center of the canvas
+	 * @param {strong} color     Valid CSS color string
+	 * @param {number} lineWidth Width of the line in px
+	 * @param {number} percent   Percentage to draw (float between -1 and 1)
+	 */
+	var drawCircle = function(color, lineWidth, percent) {
+		percent = Math.min(Math.max(-1, percent || 0), 1);
+		var isNegative = percent <= 0 ? true : false;
+
+		ctx.beginPath();
+		ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
+
+		ctx.strokeStyle = color;
+		ctx.lineWidth = lineWidth;
+
+		ctx.stroke();
+	};
+
+	/**
+	 * Draw the scale of the chart
+	 */
+	var drawScale = function() {
+		var offset;
+		var length;
+
+		ctx.lineWidth = 1;
+		ctx.fillStyle = options.scaleColor;
+
+		ctx.save();
+		for (var i = 24; i > 0; --i) {
+			if (i % 6 === 0) {
+				length = options.scaleLength;
+				offset = 0;
+			} else {
+				length = options.scaleLength * 0.6;
+				offset = options.scaleLength - length;
+			}
+			ctx.fillRect(-options.size/2 + offset, 0, length, 1);
+			ctx.rotate(Math.PI / 12);
+		}
+		ctx.restore();
+	};
+
+	/**
+	 * Request animation frame wrapper with polyfill
+	 * @return {function} Request animation frame method or timeout fallback
+	 */
+	var reqAnimationFrame = (function() {
+		return  window.requestAnimationFrame ||
+				window.webkitRequestAnimationFrame ||
+				window.mozRequestAnimationFrame ||
+				function(callback) {
+					window.setTimeout(callback, 1000 / 60);
+				};
+	}());
+
+	/**
+	 * Draw the background of the plugin including the scale and the track
+	 */
+	var drawBackground = function() {
+		if(options.scaleColor) drawScale();
+		if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
+	};
+
+  /**
+    * Canvas accessor
+   */
+  this.getCanvas = function() {
+    return canvas;
+  };
+
+  /**
+    * Canvas 2D context 'ctx' accessor
+   */
+  this.getCtx = function() {
+    return ctx;
+  };
+
+	/**
+	 * Clear the complete canvas
+	 */
+	this.clear = function() {
+		ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
+	};
+
+	/**
+	 * Draw the complete chart
+	 * @param {number} percent Percent shown by the chart between -100 and 100
+	 */
+	this.draw = function(percent) {
+		// do we need to render a background
+		if (!!options.scaleColor || !!options.trackColor) {
+			// getImageData and putImageData are supported
+			if (ctx.getImageData && ctx.putImageData) {
+				if (!cachedBackground) {
+					drawBackground();
+					cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
+				} else {
+					ctx.putImageData(cachedBackground, 0, 0);
+				}
+			} else {
+				this.clear();
+				drawBackground();
+			}
+		} else {
+			this.clear();
+		}
+
+		ctx.lineCap = options.lineCap;
+
+		// if barcolor is a function execute it and pass the percent as a value
+		var color;
+		if (typeof(options.barColor) === 'function') {
+			color = options.barColor(percent);
+		} else {
+			color = options.barColor;
+		}
+
+		// draw bar
+		drawCircle(color, options.lineWidth, percent / 100);
+	}.bind(this);
+
+	/**
+	 * Animate from some percent to some other percentage
+	 * @param {number} from Starting percentage
+	 * @param {number} to   Final percentage
+	 */
+	this.animate = function(from, to) {
+		var startTime = Date.now();
+		options.onStart(from, to);
+		var animation = function() {
+			var process = Math.min(Date.now() - startTime, options.animate.duration);
+			var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
+			this.draw(currentValue);
+			options.onStep(from, to, currentValue);
+			if (process >= options.animate.duration) {
+				options.onStop(from, to);
+			} else {
+				reqAnimationFrame(animation);
+			}
+		}.bind(this);
+
+		reqAnimationFrame(animation);
+	}.bind(this);
+};

+ 22 - 0
app/Resources/public/assets/jquery.easy-pie-chart/test/polyfills/bind.js

@@ -0,0 +1,22 @@
+// IE function.bind polyfill
+if (!Function.prototype.bind) {
+	Function.prototype.bind = function (oThis) {
+		if (typeof this !== 'function') {
+			// closest thing possible to the ECMAScript 5 internal IsCallable function
+			throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
+		}
+
+		var aArgs = Array.prototype.slice.call(arguments, 1),
+			fToBind = this,
+			fNOP = function () {},
+			fBound = function () {
+				return fToBind.apply(this instanceof fNOP && oThis ? this : oThis,
+			aArgs.concat(Array.prototype.slice.call(arguments)));
+		};
+
+		fNOP.prototype = this.prototype;
+		fBound.prototype = new fNOP();
+
+		return fBound;
+	};
+}

+ 68 - 0
app/Resources/public/assets/jquery.easy-pie-chart/test/unit/angular.directive.js

@@ -0,0 +1,68 @@
+describe('angular easypiechart directive', function() {
+    var $compile, $rootScope, scope;
+
+    beforeEach(module('easypiechart'));
+
+    beforeEach(inject(function(_$compile_, $rootScope){
+        scope = $rootScope;
+        $compile = _$compile_;
+    }));
+
+    it('should have percentage default value 0', function (done) {
+        scope.percent = null;
+        var element = angular.element('<div easypiechart percent="percent" options="options"></div>');
+        $compile(element)(scope);
+        scope.$digest();
+        expect(element.isolateScope().percent).toBe(0);
+    });
+
+    it('inserts the element with a canvas element', function() {
+        scope.percent = -45;
+        scope.options = {};
+        var element = angular.element('<div easypiechart percent="percent" options="options"></div>');
+        $compile(element)(scope);
+        scope.$digest();
+        expect(element.html()).toContain('canvas');
+    });
+
+    it('gets the options right', function (done) {
+        scope.percent = 0;
+        scope.options = {
+            animate:{
+                duration:0,
+                enabled:false
+            },
+            barColor:'#2C3E50',
+            scaleColor:false,
+            lineWidth:20,
+            lineCap:'circle'
+        };
+        var element = angular.element('<div easypiechart percent="percent" options="options"></div>');
+        $compile(element)(scope);
+        scope.$digest();
+        expect(element.isolateScope().options.animate.duration).toBe(0);
+        expect(element.isolateScope().options.lineCap).toBe('circle');
+    });
+
+    it('has its own default options', function (done) {
+        scope.percent = 0;
+        scope.options = {};
+        var element = angular.element('<div easypiechart percent="percent" options="options"></div>');
+        $compile(element)(scope);
+        scope.$digest();
+        expect(element.isolateScope().options.size).toBe(110);
+        expect(element.isolateScope().options.animate.enabled).toBe(true);
+    });
+
+    it('takes size option the right way', function() {
+        scope.percent = 0;
+        scope.options = {
+            size: 200
+        };
+        var element = angular.element('<div easypiechart percent="percent" options="options"></div>');
+        $compile(element)(scope);
+        scope.$digest();
+        expect(element.html()).toContain('height="200"');
+        expect(element.html()).toContain('width="200"');
+    });
+});

+ 61 - 0
app/Resources/public/assets/jquery.easy-pie-chart/test/unit/jquery.js

@@ -0,0 +1,61 @@
+describe('Unit testing jQuery version of easy pie chart', function() {
+	var $el;
+
+	var createInstance = function(options, el) {
+		options = options || {};
+		el = el || '<span class="chart"></span>';
+		return function() {
+			$el = $(el);
+			$('body').append($el);
+			$el.easyPieChart(options);
+		};
+	};
+
+	describe('initialize plugin', function() {
+		beforeEach(createInstance());
+
+		it('should insert a canvas element', function() {
+			expect($el.html()).toContain('canvas');
+		});
+	});
+
+
+	describe('takes size option and', function() {
+		var $canvas;
+		beforeEach(createInstance({
+			size: 200
+		}));
+
+		beforeEach(function() {
+			$canvas = $el.find('canvas');
+		});
+
+		it('set correct width', function() {
+			expect($canvas.width()).toBe(200);
+		});
+
+		it('set correct height', function() {
+			expect($canvas.height()).toBe(200);
+		});
+	});
+
+	describe('options should be overwritable by data attributes', function() {
+		var $canvas;
+		beforeEach(createInstance({
+			size: 200
+		}, '<span class="chart" data-size="400"></span>'));
+
+		beforeEach(function() {
+			$canvas = $el.find('canvas');
+		});
+
+		it('overwrite width', function() {
+			expect($canvas.width()).toBe(400);
+		});
+
+		it('overwrite height', function() {
+			expect($canvas.height()).toBe(400);
+		});
+	});
+
+});

+ 108 - 0
app/Resources/public/css/base.css

@@ -602,6 +602,114 @@ input[type=checkbox], input[type=radio]{
 #exercise-description .panel-heading a.collapsed{
     background: url("../../main/img/icons/22/arrow-down-collapse.png") no-repeat left center;
 }
+/* REPORTS */
+.panel-default.panel-view{
+    border: 1px solid #e4e4e4;
+    box-shadow: 0 2px 2px rgba(204, 197, 185, 0.5);
+}
+.card {
+    border-radius: 6px;
+    box-shadow: 0 2px 2px rgba(204, 197, 185, 0.5);
+    background-color: #FFFFFF;
+    color: #252422;
+    margin-bottom: 20px;
+    position: relative;
+    z-index: 1;
+    border: 1px solid #e4e4e4;
+}
+.card .content {
+    padding: 15px 15px 10px 15px;
+}
+.card .icon-big {
+    font-size: 2.5em;
+    min-height: 64px;
+}
+.card .numbers {
+    text-align: left;
+}
+.card .numbers h2{
+    font-size: 3.2em;
+    margin-top: 10px;
+    color: #666666;
+}
+.card .icon-big{
+    width: 65px;
+    height: 65px;
+    border-radius: 50%;
+    text-align: center;
+    vertical-align: middle;
+    margin-left: 25px;
+}
+.card .icon-student{
+    background: #f1c435;
+}
+.card .icon-studentboss{
+    background: #4b73eb;
+}
+.card .icon-teachers{
+    background: #50bbc1;
+}
+.card .icon-humanresources{
+    background: #68ceeb;
+}
+.card .icon-big i {
+    line-height: 66px;
+    color: #fff;
+}
+.card .card-title{
+    text-align: center;
+    font-size: 12px;
+    padding-bottom: 10px;
+    padding-top: 10px;
+    display: inline-block;
+    width: 100%;
+}
+.card .card-title a{
+    font-weight: bold;
+}
+.panel-view{
+    padding: 20px;
+    text-align: center;
+}
+.easypiechart {
+    position: relative;
+    text-align: center;
+    width: 120px;
+    height: 120px;
+    margin: 20px auto 10px auto;
+}
+#easypiechart-blue .percent { color: #30a5ff;}
+#easypiechart-teal .percent { color: #1ebfae;}
+#easypiechart-orange .percent { color: #ffb53e;}
+#easypiechart-red .percent { color: #ef4040;}
+
+.easypiechart .percent {
+    display: block;
+    position: absolute;
+    font-size: 26px;
+    top: 38px;
+    width: 120px;
+}
+.easypiechart-link{
+    padding-bottom: 5px;
+    padding-top: 5px;
+    display: inline-block;
+    width: 100%;
+}
+.item-report{
+    text-align: center;
+    min-height: 200px;
+}
+.item-report .panel-default{
+    background-color: #ededed;
+    border: 1px solid #e4e4e4;
+    box-shadow: 0 2px 2px rgba(204, 197, 185, 0.5);
+}
+.item-report .item-report-number{
+    font-size: 35px;
+    font-weight: bold;
+    color: #666666;
+}
 /*****************************************************
  *              AGENDA                               *
  *****************************************************/

+ 3 - 2
bower.json

@@ -31,8 +31,9 @@
     "pwstrength-bootstrap": "2.1.0",
     "readmore-js": "2.1.0",
     "qtip2": "*",
-    "js-cookie" : "2.1.*",
-    "flag-icon-css" : "*"
+    "js-cookie": "2.1.*",
+    "flag-icon-css": "*",
+    "jquery.easy-pie-chart": "^2.1.6"
   },
   "resolutions": {
     "jquery": "2.1.4"

BIN
main/img/icons/128/skill_acquirers.png


BIN
main/img/icons/16/skill_acquirers.png


BIN
main/img/icons/22/skill_acquirers.png


BIN
main/img/icons/32/skill_acquirers.png


BIN
main/img/icons/48/skill_acquirers.png


BIN
main/img/icons/64/skill_acquirers.png


+ 103 - 160
main/mySpace/index.php

@@ -15,10 +15,12 @@ $cidReset = true;
 require_once __DIR__.'/../inc/global.inc.php';
 
 $htmlHeadXtra[] = api_get_jqgrid_js();
+$htmlHeadXtra[] = '<script type="text/javascript" src="'
+    .api_get_path(WEB_PUBLIC_PATH).'assets/jquery.easy-pie-chart/dist/jquery.easypiechart.js"></script>';
 // the section (for the tabs)
 $this_section = SECTION_TRACKING;
 //for HTML editor repository
-Session::erase('this_section');
+//Session::erase('this_section');
 
 ob_start();
 $nameTools = get_lang('MySpace');
@@ -36,10 +38,10 @@ $skipData = api_get_configuration_value('tracking_skip_generic_data');
 
 // Access control
 api_block_anonymous_users();
-
+/*
 if (!$export_csv) {
-    Display :: display_header($nameTools);
-}
+     Display :: display_header($nameTools);
+} */
 
 if ($is_session_admin) {
     header('location:session.php');
@@ -127,43 +129,72 @@ if ($is_drh) {
     );
 }
 
-echo '<div id="actions" class="actions">';
-echo '<span style="float:right">';
+$actionsRight = '';
+$actionsLeft = '';
 if ($display == 'useroverview' || $display == 'sessionoverview' || $display == 'courseoverview') {
-    echo '<a href="'.api_get_self().'?display='.$display.'&export=csv&view='.$view.'">';
-    echo Display::return_icon("export_csv.png", get_lang('ExportAsCSV'), [], 32);
-    echo '</a>';
+    $actionsRight .= Display::url(
+        Display::return_icon(
+            "export_csv.png",
+            get_lang('ExportAsCSV'),
+            null,
+            ICON_SIZE_MEDIUM),
+        api_get_self() . '?display=' . $display . '&export=csv&view=' . $view
+    );
 }
-echo '<a href="javascript: void(0);" onclick="javascript: window.print()">'.
-    Display::return_icon('printer.png', get_lang('Print'), '', ICON_SIZE_MEDIUM).'</a>';
-echo '</span>';
+$actionsRight .= Display::url(
+    Display::return_icon('printer.png',
+        get_lang('Print'),
+        null,
+        ICON_SIZE_MEDIUM),
+    'javascript: void(0);',
+    ['onclick'=>'javascript: window.print()']
+);
 
 if (!empty($session_id) &&
     !in_array($display, ['accessoverview', 'lpprogressoverview', 'progressoverview', 'exerciseprogress', 'surveyoverview'])
 ) {
-    echo '<a href="index.php">'.Display::return_icon('back.png', get_lang('Back'), '', ICON_SIZE_MEDIUM).'</a>';
+    $actionsLeft .= Display::url(Display::return_icon(
+        'back.png',
+        get_lang('Back'),
+        null,
+        ICON_SIZE_MEDIUM),
+        'index.php');
     if (!api_is_platform_admin()) {
         if (api_get_setting('add_users_by_coach') == 'true') {
             if ($is_coach) {
-                echo "<div align=\"right\">";
-                echo '<a href="user_import.php?id_session='.$session_id.'&action=export&amp;type=xml">'.
-                        Display::return_icon('excel.gif', get_lang('ImportUserList')).'&nbsp;'.get_lang('ImportUserList').'</a>';
-                echo "</div><br />";
+                $actionsLeft .= Display::url(
+                    Display::return_icon('excel.png',
+                        get_lang('ImportUserList'),
+                        null,
+                        ICON_SIZE_MEDIUM),
+                    'user_import.php?id_session='.$session_id.'&action=export&amp;type=xml');
             }
         }
     } else {
-        echo "<div align=\"right\">";
-        echo '<a href="user_import.php?id_session='.$session_id.'&action=export&amp;type=xml">'.
-                Display::return_icon('excel.gif', get_lang('ImportUserList')).'&nbsp;'.get_lang('ImportUserList').'</a>';
-        echo "</div><br />";
+        Display::url(
+            Display::return_icon('excel.png',
+            get_lang('ImportUserList'),
+            null,
+            ICON_SIZE_MEDIUM),
+            'user_import.php?id_session='.$session_id.'&action=export&amp;type=xml');
     }
+
 } else {
-    echo Display::url(
-        Display::return_icon('stats.png', get_lang('MyStats'), '', ICON_SIZE_MEDIUM),
+
+    $actionsLeft .= Display::url(
+        Display::return_icon(
+            'stats.png',
+            get_lang('MyStats'),
+            null,
+            ICON_SIZE_MEDIUM),
         api_get_path(WEB_CODE_PATH)."auth/my_progress.php"
     );
-    echo Display::url(
-        Display::return_icon("certificate_list.png", get_lang("GradebookSeeListOfStudentsCertificates"), [], ICON_SIZE_MEDIUM),
+    $actionsLeft .= Display::url(
+        Display::return_icon(
+            "certificate_list.png",
+            get_lang("GradebookSeeListOfStudentsCertificates"),
+            null,
+            ICON_SIZE_MEDIUM),
         api_get_path(WEB_CODE_PATH)."gradebook/certificate_report.php"
     );
 }
@@ -175,13 +206,11 @@ if (empty($session_id) ||
 ) {
     if ($nb_menu_items > 1) {
         foreach ($menu_items as $key => $item) {
-            echo $item;
+            $actionsLeft .= $item;
         }
     }
 }
 
-echo '</div>';
-
 $userId = api_get_user_id();
 $stats = Tracking::getStats($userId, true);
 
@@ -213,103 +242,20 @@ $daysAgo = 7;
 $studentIds = [];
 $avg_courses_per_student = 0;
 
-$linkAddUser = null;
-$linkCourseDetailsAsTeacher = null;
-$linkAddCourse = null;
-$linkAddSession = null;
+$view = new Template($nameTools);
+$view->assign('students', $numberStudents);
+$view->assign('studentbosses', $numberStudentBosses);
+$view->assign('numberTeachers', $numberTeachers);
+$view->assign('humanresources', $countHumanResourcesUsers);
+$view->assign(
+    'total_user',
+    $numberStudents + $numberStudentBosses + $numberTeachers + $countHumanResourcesUsers);
+$view->assign('studentboss', STUDENT_BOSS);
+$view->assign('drh', DRH);
+$view->assign('stats', $stats);
 
-if (api_is_platform_admin()) {
-    $linkAddUser = ' '.Display::url(
-        Display::return_icon('2rightarrow.png', get_lang('Add')),
-        api_get_path(WEB_CODE_PATH).'admin/dashboard_add_users_to_user.php?user='.api_get_user_id(),
-        ['class' => '']
-    );
-    $linkCourseDetailsAsTeacher = ' '.Display::url(
-        Display::return_icon('2rightarrow.png', get_lang('Details')),
-        api_get_path(WEB_CODE_PATH).'mySpace/course.php',
-        ['class' => '']
-    );
-    $linkAddCourse = ' '.Display::url(
-        Display::return_icon('2rightarrow.png', get_lang('Details')),
-        api_get_path(WEB_CODE_PATH).'mySpace/course.php?follow',
-        ['class' => '']
-    );
-    $linkAddSession = ' '.Display::url(
-        Display::return_icon('2rightarrow.png', get_lang('Add')),
-        api_get_path(WEB_CODE_PATH).'admin/dashboard_add_sessions_to_user.php?user='.api_get_user_id(),
-        ['class' => '']
-    );
-}
 
-echo Display::page_subheader(get_lang('Overview'));
-echo '<div class="report_section">
-        <table class="table table-bordered table-striped">
-            <tr>
-                <td>'.Display::url(
-                    get_lang('FollowedStudents'),
-                    api_get_path(WEB_CODE_PATH).'mySpace/student.php'
-                ).'</td>
-                <td align="right">'.$numberStudents.'</td>
-            </tr>
-            <tr>
-                <td>'.Display::url(
-                    get_lang('FollowedStudentBosses'),
-                    api_get_path(WEB_CODE_PATH).'mySpace/users.php?status='.STUDENT_BOSS
-                ).'</td>
-                <td align="right">'.$numberStudentBosses.'</td>
-            </tr>
-            <tr>
-                <td>'.Display::url(
-                    get_lang('FollowedTeachers'),
-                    api_get_path(WEB_CODE_PATH).'mySpace/teachers.php'
-                ).
-                '</td>
-                <td align="right">'.$numberTeachers.'</td>
-            </tr>
-            <tr>
-                <td>'.Display::url(
-                get_lang('FollowedHumanResources'),
-                api_get_path(WEB_CODE_PATH).'mySpace/users.php?status='.DRH
-            ).
-            '</td>
-            <td align="right">'.$countHumanResourcesUsers.'</td>
-            </tr>
-            <tr>
-             <td>'.Display::url(
-                get_lang('FollowedUsers'),
-                api_get_path(WEB_CODE_PATH).'mySpace/users.php'
-            ).
-            '</td>
-                <td align="right">'.($numberStudents + $numberStudentBosses + $numberTeachers + $countHumanResourcesUsers).$linkAddUser.'</td>
-            </tr>
-            <tr>
-                <td>'.Display::url(
-                    get_lang('AssignedCourses'),
-                    api_get_path(WEB_CODE_PATH).'mySpace/course.php'
-                ).
-                '</td>
-                <td align="right">'.$countCourses.$linkCourseDetailsAsTeacher.'</td>
-            </tr>
-            <tr>
-                <td>'.Display::url(
-                    get_lang('FollowedCourses'),
-                    api_get_path(WEB_CODE_PATH).'mySpace/course.php?follow'
-                ).
-                '</td>
-                <td align="right">'.$countAssignedCourses.$linkAddCourse.'</td>
-            </tr>
-            <tr>
-                <td>'.Display::url(
-                    get_lang('FollowedSessions'),
-                    api_get_path(WEB_CODE_PATH).'mySpace/session.php'
-                ).
-                '</td>
-            <td align="right">'.$countSessions.$linkAddSession.'</td>
-            </tr>
-            </table>';
-echo '</div>';
-
-echo Display::page_subheader(get_lang('Students').' ('.$numberStudents.')');
+//echo Display::page_subheader(get_lang('Students').' ('.$numberStudents.')');
 
 $form = new FormValidator(
     'search_user',
@@ -317,7 +263,6 @@ $form = new FormValidator(
     api_get_path(WEB_CODE_PATH).'mySpace/student.php'
 );
 $form = Tracking::setUserSearchForm($form);
-$form->display();
 
 $skipData = api_get_configuration_value('tracking_skip_generic_data');
 
@@ -347,8 +292,12 @@ if ($skipData == false) {
         $csv_content[] = [get_lang('InactivesStudents'), $nb_inactive_students];
         $csv_content[] = [get_lang('AverageTimeSpentOnThePlatform'), $totalTimeSpent];
         $csv_content[] = [get_lang('AverageCoursePerStudent'), $avg_courses_per_student];
-        $csv_content[] = [get_lang('AverageProgressInLearnpath'), is_null($avgTotalProgress) ? null : round($avgTotalProgress, 2).'%'];
-        $csv_content[] = [get_lang('AverageResultsToTheExercices'), is_null($averageScore) ? null : round($averageScore, 2).'%'];
+        $csv_content[] = [get_lang('AverageProgressInLearnpath'), is_null($avgTotalProgress)
+            ? null
+            : round($avgTotalProgress, 2).'%'];
+        $csv_content[] = [get_lang('AverageResultsToTheExercices'), is_null($averageScore)
+            ? null
+            : round($averageScore, 2).'%'];
         $csv_content[] = [get_lang('AveragePostsInForum'), $posts];
         $csv_content[] = [get_lang('AverageAssignments'), $numberAssignments];
         $csv_content[] = [];
@@ -376,43 +325,35 @@ if ($skipData == false) {
             $sessionIdList,
             $studentIds
         );
-
-        // html part
-        echo '<div class="report_section">
-                <table class="table table-bordered table-striped">
-                    <tr>
-                        <td>'.get_lang('AverageCoursePerStudent').'</td>
-                        <td align="right">'.(is_null($avg_courses_per_student) ? '' : round($avg_courses_per_student, 2)).'</td>
-                    </tr>
-                    <tr>
-                        <td>'.get_lang('InactivesStudents').'</td>
-                        <td align="right">'.$nb_inactive_students.'</td>
-                    </tr>
-                    <tr>
-                        <td>'.get_lang('AverageTimeSpentOnThePlatform').'</td>
-                        <td align="right">'.(is_null($totalTimeSpent) ? '' : api_time_to_hms($totalTimeSpent)).'</td>
-                    </tr>
-                    <tr>
-                        <td>'.get_lang('AverageProgressInLearnpath').'</td>
-                        <td align="right">'.(is_null($avgTotalProgress) ? '' : round($avgTotalProgress, 2).'%').'</td>
-                    </tr>
-                    <tr>
-                        <td>'.get_lang('AvgCourseScore').'</td>
-                        <td align="right">'.(is_null($averageScore) ? '' : round($averageScore, 2).'%').'</td>
-                    </tr>
-                    <tr>
-                        <td>'.get_lang('AveragePostsInForum').'</td>
-                        <td align="right">'.(is_null($posts) ? '' : round($posts, 2)).'</td>
-                    </tr>
-                    <tr>
-                        <td>'.get_lang('AverageAssignments').'</td>
-                        <td align="right">'.(is_null($numberAssignments) ? '' : round($numberAssignments, 2)).'</td>
-                    </tr>
-                </table>
-             </div>';
+        $report['AverageCoursePerStudent'] = is_null($avg_courses_per_student)
+            ? ''
+            : round($avg_courses_per_student, 2);
+        $report['InactivesStudents'] = $nb_inactive_students;
+        $report['AverageTimeSpentOnThePlatform'] = is_null($totalTimeSpent)
+            ? '00:00:00'
+            : api_time_to_hms($totalTimeSpent);
+        $report['AverageProgressInLearnpath'] = is_null($avgTotalProgress)
+            ? ''
+            : round($avgTotalProgress, 2).'%';
+        $report['AvgCourseScore'] = is_null($averageScore) ? '0' : round($averageScore, 2).'%';
+        $report['AveragePostsInForum'] = is_null($posts) ? '0' : round($posts, 2);
+        $report['AverageAssignments'] = is_null($numberAssignments) ? '' : round($numberAssignments, 2);
+        $view->assign('report', $report);
     }
 }
 
+
+$view->assign('header', $nameTools);
+$view->assign('form', $form->returnForm());
+$view->assign('actions',Display::toolbarAction('toolbar', [$actionsLeft, $actionsRight]));
+$view->assign('title', get_lang('Students').' ('.$numberStudents.')');
+
+$template = $view->get_template('my_space/index.tpl');
+$content = $view->fetch($template);
+$view->assign('content', $content);
+$view->display_one_col_template();
+
+
 // Send the csv file if asked
 if ($export_csv) {
     ob_end_clean();
@@ -420,6 +361,8 @@ if ($export_csv) {
     exit;
 }
 
+/*
 if (!$export_csv) {
     Display::display_footer();
 }
+*/

+ 15 - 18
main/mySpace/student.php

@@ -1,7 +1,7 @@
 <?php
 /* For licensing terms, see /license.txt */
 /**
- * Student report.
+ * Report on students subscribed to courses I am teaching
  *
  * @package chamilo.reporting
  */
@@ -38,15 +38,16 @@ if (isset($_GET["user_id"]) && $_GET["user_id"] != "" && isset($_GET["type"]) &&
 
 function get_count_users()
 {
-    $keyword = isset($_GET['keyword']) ? Security::remove_XSS($_GET['keyword']) : null;
-    $active = isset($_GET['active']) ? (int) $_GET['active'] : 1;
     $sleepingDays = isset($_GET['sleeping_days']) ? (int) $_GET['sleeping_days'] : null;
+    $active = isset($_GET['active']) ? (int) $_GET['active'] : 1;
+    $keyword = isset($_GET['keyword']) ? Security::remove_XSS($_GET['keyword']) : null;
 
     $lastConnectionDate = null;
     if (!empty($sleepingDays)) {
         $lastConnectionDate = api_get_utc_datetime(strtotime($sleepingDays.' days ago'));
     }
-    $count = SessionManager::getCountUserTracking(
+
+    return SessionManager::getCountUserTracking(
         $keyword,
         $active,
         $lastConnectionDate,
@@ -54,17 +55,15 @@ function get_count_users()
         null,
         api_is_student_boss() ? null : STUDENT
     );
-
-    return $count;
 }
 
 function get_users($from, $limit, $column, $direction)
 {
+    global $export_csv;
     $active = isset($_GET['active']) ? $_GET['active'] : 1;
     $keyword = isset($_GET['keyword']) ? Security::remove_XSS($_GET['keyword']) : null;
     $sleepingDays = isset($_GET['sleeping_days']) ? (int) $_GET['sleeping_days'] : null;
     $sessionId = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
-    $export_csv = isset($_GET['export']) && $_GET['export'] == 'csv' ? true : false;
 
     $lastConnectionDate = null;
     if (!empty($sleepingDays)) {
@@ -72,11 +71,10 @@ function get_users($from, $limit, $column, $direction)
     }
     $is_western_name_order = api_is_western_name_order();
     $coach_id = api_get_user_id();
-
+    $column = 'u.user_id';
     $drhLoaded = false;
 
     if (api_is_drh()) {
-        $column = 'u.user_id';
         if (api_drh_can_access_all_session_content()) {
             $students = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
                 'drh_all',
@@ -97,7 +95,7 @@ function get_users($from, $limit, $column, $direction)
         }
     }
 
-    if ($drhLoaded == false) {
+    if ($drhLoaded === false) {
         $students = UserManager::getUsersFollowedByUser(
             api_get_user_id(),
             api_is_student_boss() ? null : STUDENT,
@@ -130,13 +128,14 @@ function get_users($from, $limit, $column, $direction)
             foreach ($courses as $course_code) {
                 $courseInfo = api_get_course_info($course_code);
                 $courseId = $courseInfo['real_id'];
-                if (CourseManager :: is_user_subscribed_in_course($student_id, $course_code, true)) {
-                    $avg_time_spent += Tracking :: get_time_spent_on_the_course($student_id, $courseId, $sessionId);
-                    $my_average = Tracking :: get_avg_student_score($student_id, $course_code);
+
+                if (CourseManager::is_user_subscribed_in_course($student_id, $course_code, true)) {
+                    $avg_time_spent += Tracking::get_time_spent_on_the_course($student_id, $courseId, $_GET['id_session']);
+                    $my_average = Tracking::get_avg_student_score($student_id, $course_code);
                     if (is_numeric($my_average)) {
                         $avg_student_score += $my_average;
                     }
-                    $avg_student_progress += Tracking :: get_avg_student_progress($student_id, $course_code);
+                    $avg_student_progress += Tracking::get_avg_student_progress($student_id, $course_code);
                     $nb_courses_student++;
                 }
             }
@@ -267,8 +266,7 @@ if (api_is_drh()) {
     );
 }
 
-$actionsRight = '';
-$actionsRight .= Display::url(
+$actionsRight = Display::url(
     Display::return_icon('printer.png', get_lang('Print'), [], ICON_SIZE_MEDIUM),
     'javascript: void(0);',
     ['onclick' => 'javascript: window.print();']
@@ -346,8 +344,7 @@ if ($export_csv) {
 } else {
     Display::display_header($nameTools);
     echo $toolbar;
-    $page_title = get_lang('Students');
-    echo Display::page_subheader($page_title);
+    echo Display::page_subheader($nameTools);
     if (isset($active)) {
         if ($active) {
             $activeLabel = get_lang('ActiveUsers');

+ 77 - 27
main/mySpace/users.php

@@ -1,8 +1,7 @@
 <?php
 /* For licensing terms, see /license.txt */
-
 /**
- * Student report.
+ * Report on users followed (filtered by status given in URL)
  *
  * @package chamilo.reporting
  */
@@ -10,6 +9,8 @@ $cidReset = true;
 
 require_once __DIR__.'/../inc/global.inc.php';
 
+$nameTools = get_lang('Users');
+
 $export_csv = isset($_GET['export']) && $_GET['export'] == 'csv' ? true : false;
 $keyword = isset($_GET['keyword']) ? Security::remove_XSS($_GET['keyword']) : null;
 $active = isset($_GET['active']) ? intval($_GET['active']) : 1;
@@ -20,10 +21,16 @@ api_block_anonymous_users();
 
 $this_section = SECTION_TRACKING;
 
-$interbreadcrumb[] = ["url" => "index.php", "name" => get_lang('MySpace')];
+$interbreadcrumb[] = [
+    "url" => "index.php",
+    "name" => get_lang('MySpace'),
+];
 
 if (isset($_GET["user_id"]) && $_GET["user_id"] != "" && !isset($_GET["type"])) {
-    $interbreadcrumb[] = ["url" => "teachers.php", "name" => get_lang('Teachers')];
+    $interbreadcrumb[] = [
+        "url" => "teachers.php",
+        "name" => get_lang('Teachers'),
+    ];
 }
 
 if (isset($_GET["user_id"]) && $_GET["user_id"] != "" && isset($_GET["type"]) && $_GET["type"] == "coach") {
@@ -32,8 +39,8 @@ if (isset($_GET["user_id"]) && $_GET["user_id"] != "" && isset($_GET["type"]) &&
 
 function get_count_users()
 {
-    $sleepingDays = isset($_GET['sleeping_days']) ? intval($_GET['sleeping_days']) : null;
-    $active = isset($_GET['active']) ? $_GET['active'] : 1;
+    $sleepingDays = isset($_GET['sleeping_days']) ? (int) $_GET['sleeping_days'] : null;
+    $active = isset($_GET['active']) ? (int) $_GET['active'] : 1;
     $keyword = isset($_GET['keyword']) ? Security::remove_XSS($_GET['keyword']) : null;
     $status = isset($_GET['status']) ? Security::remove_XSS($_GET['status']) : null;
 
@@ -56,19 +63,18 @@ function get_users($from, $limit, $column, $direction)
 {
     $active = isset($_GET['active']) ? $_GET['active'] : 1;
     $keyword = isset($_GET['keyword']) ? Security::remove_XSS($_GET['keyword']) : null;
-    $sleepingDays = isset($_GET['sleeping_days']) ? intval($_GET['sleeping_days']) : null;
-    $status = isset($_GET['status']) ? Security::remove_XSS($_GET['status']) : null;
+    $sleepingDays = isset($_GET['sleeping_days']) ? (int) $_GET['sleeping_days'] : null;
     $sessionId = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
+    $status = isset($_GET['status']) ? Security::remove_XSS($_GET['status']) : null;
 
     $lastConnectionDate = null;
     if (!empty($sleepingDays)) {
         $lastConnectionDate = api_get_utc_datetime(strtotime($sleepingDays.' days ago'));
     }
-
     $is_western_name_order = api_is_western_name_order();
     $coach_id = api_get_user_id();
-    $column = 'u.user_id';
     $drhLoaded = false;
+
     if (api_is_drh()) {
         if (api_drh_can_access_all_session_content()) {
             $students = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
@@ -109,11 +115,10 @@ function get_users($from, $limit, $column, $direction)
     }
 
     $all_datas = [];
-
     foreach ($students as $student_data) {
         $student_id = $student_data['user_id'];
         if (isset($_GET['id_session'])) {
-            $courses = Tracking :: get_course_list_in_session_from_student($student_id, $_GET['id_session']);
+            $courses = Tracking :: get_course_list_in_session_from_student($student_id, $sessionId);
         }
 
         $avg_time_spent = $avg_student_score = $avg_student_progress = 0;
@@ -153,6 +158,7 @@ function get_users($from, $limit, $column, $direction)
             $row[] = $student_data['lastname'];
             $row[] = $student_data['firstname'];
         }
+
         $string_date = Tracking::get_last_connection_date($student_id, true);
         $first_date = Tracking::get_first_connection_date($student_id);
         $row[] = $first_date;
@@ -165,6 +171,7 @@ function get_users($from, $limit, $column, $direction)
             $detailsLink = '<a href="myStudents.php?student='.$student_id.'">
 				            '.Display::return_icon('2rightarrow.png', get_lang('Details')).'</a>';
         }
+
         $row[] = $detailsLink;
         $all_datas[] = $row;
     }
@@ -183,11 +190,30 @@ $actionsLeft = '';
 
 if (api_is_drh()) {
     $menu_items = [
-        Display::url(Display::return_icon('stats.png', get_lang('MyStats'), '', ICON_SIZE_MEDIUM), api_get_path(WEB_CODE_PATH)."auth/my_progress.php"),
-        Display::url(Display::return_icon('user_na.png', get_lang('Students'), [], ICON_SIZE_MEDIUM), '#'),
-        Display::url(Display::return_icon('teacher.png', get_lang('Trainers'), [], ICON_SIZE_MEDIUM), 'teachers.php'),
-        Display::url(Display::return_icon('course.png', get_lang('Courses'), [], ICON_SIZE_MEDIUM), 'course.php'),
-        Display::url(Display::return_icon('session.png', get_lang('Sessions'), [], ICON_SIZE_MEDIUM), 'session.php'),
+        Display::url(
+            Display::return_icon('stats.png', get_lang('MyStats'), '', ICON_SIZE_MEDIUM),
+            api_get_path(WEB_CODE_PATH)."auth/my_progress.php"
+        ),
+        Display::url(
+            Display::return_icon('user_na.png', get_lang('Students'), [], ICON_SIZE_MEDIUM),
+            '#'
+        ),
+        Display::url(
+            Display::return_icon('teacher.png', get_lang('Trainers'), [], ICON_SIZE_MEDIUM),
+            'teachers.php'
+        ),
+        Display::url(
+            Display::return_icon('course.png', get_lang('Courses'), [], ICON_SIZE_MEDIUM),
+            'course.php'
+        ),
+        Display::url(
+            Display::return_icon('session.png', get_lang('Sessions'), [], ICON_SIZE_MEDIUM),
+            'session.php'
+        ),
+        Display::url(
+            Display::return_icon('skills.png', get_lang('Skills'), [], ICON_SIZE_MEDIUM),
+            'skills.php'
+        ),
     ];
 
     $nb_menu_items = count($menu_items);
@@ -196,6 +222,28 @@ if (api_is_drh()) {
             $actionsLeft .= $item;
         }
     }
+} elseif (api_is_student_boss()) {
+    $actionsLeft .= Display::url(
+        Display::return_icon('stats.png', get_lang('MyStats'), '', ICON_SIZE_MEDIUM),
+        api_get_path(WEB_CODE_PATH)."auth/my_progress.php"
+    );
+    $actionsLeft .= Display::url(
+        Display::return_icon('user_na.png', get_lang('Students'), [], ICON_SIZE_MEDIUM),
+        '#'
+    );
+    $actionsLeft .= Display::url(
+        Display::return_icon("statistics.png", get_lang("CompanyReport"), [], ICON_SIZE_MEDIUM),
+        api_get_path(WEB_CODE_PATH)."mySpace/company_reports.php"
+    );
+    $actionsLeft .= Display::url(
+        Display::return_icon(
+            "certificate_list.png",
+            get_lang("GradebookSeeListOfStudentsCertificates"),
+            [],
+            ICON_SIZE_MEDIUM
+        ),
+        api_get_path(WEB_CODE_PATH)."gradebook/certificate_report.php"
+    );
 }
 
 $actionsRight = Display::url(
@@ -207,6 +255,7 @@ $actionsRight .= Display::url(
     Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), [], ICON_SIZE_MEDIUM),
     api_get_self().'?export=csv&keyword='.$keyword
 );
+
 $toolbar = Display::toolbarAction('toolbar-user', [$actionsLeft, $actionsRight]);
 
 $table = new SortableTable(
@@ -255,8 +304,11 @@ if ($export_csv) {
     }
 }
 
-$form = new FormValidator('search_user', 'get', api_get_path(WEB_CODE_PATH).'mySpace/users.php');
-
+$form = new FormValidator(
+    'search_user',
+    'get',
+    api_get_path(WEB_CODE_PATH).'mySpace/users.php'
+);
 $form->addElement(
     'select',
     'status',
@@ -271,22 +323,20 @@ $form->addElement(
 $form = Tracking::setUserSearchForm($form);
 $form->setDefaults($params);
 
-// send the csv file if asked
-$content = $table->get_table_data();
-
 if ($export_csv) {
+    // send the csv file if asked
+    $content = $table->get_table_data();
     foreach ($content as &$row) {
         unset($row[4]);
     }
     $csv_content = array_merge($csv_header, $content);
     ob_end_clean();
-    Export :: arrayToCsv($csv_content, 'reporting_student_list');
+    Export::arrayToCsv($csv_content, 'reporting_student_list');
     exit;
 } else {
-    Display::display_header(get_lang('Users'));
+    Display::display_header($nameTools);
     echo $toolbar;
-    $page_title = get_lang('Users');
-    echo Display::page_subheader($page_title);
+    echo Display::page_subheader($nameTools);
     if (isset($active)) {
         if ($active) {
             $activeLabel = get_lang('ActiveUsers');
@@ -299,4 +349,4 @@ if ($export_csv) {
     $table->display();
 }
 
-Display :: display_footer();
+Display::display_footer();

+ 301 - 0
main/template/default/my_space/index.tpl

@@ -0,0 +1,301 @@
+<div class="search-student">
+    {{ form }}
+</div>
+
+<div class="page-header">
+    <h4>
+        {{ 'Overview' | get_lang  }}
+    </h4>
+</div>
+
+<div class="view-global-followed">
+    <div class="row">
+        <div class="col-lg-3 col-sm-3">
+            <div class="card">
+                <div class="content">
+                    <div class="card-title"><a href="{{ _p.web_main }}mySpace/student.php">{{ 'FollowedStudents' | get_lang }}</a></div>
+                    <div class="row">
+                        <div class="col-xs-5">
+                            <div class="icon-big icon-student text-center">
+                                <i class="fa fa-graduation-cap" aria-hidden="true"></i>
+                            </div>
+                        </div>
+                        <div class="col-xs-7">
+                            <div class="numbers">
+
+                                <h2>{{ students }}</h2>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="col-lg-3 col-sm-3">
+            <div class="card">
+                <div class="content">
+                    <div class="card-title"><a href="{{ _p.web_main }}mySpace/users.php?status={{ studentboss }}">{{ 'FollowedStudentBosses' | get_lang }}</a></div>
+                    <div class="row">
+                        <div class="col-xs-5">
+                            <div class="icon-big icon-studentboss text-center">
+                                <i class="fa fa-address-book" aria-hidden="true"></i>
+                            </div>
+                        </div>
+                        <div class="col-xs-7">
+                            <div class="numbers">
+
+                                <h2>{{ studentbosses }}</h2>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="col-lg-3 col-sm-3">
+            <div class="card">
+                <div class="content">
+                    <div class="card-title"><a href="{{ _p.web_main }}mySpace/teachers.php">{{ 'FollowedTeachers' | get_lang }}</a></div>
+                    <div class="row">
+                        <div class="col-xs-5">
+                            <div class="icon-big icon-teachers text-center">
+                                <i class="fa fa-book" aria-hidden="true"></i>
+                            </div>
+                        </div>
+                        <div class="col-xs-7">
+                            <div class="numbers">
+
+                                <h2>{{ numberTeachers }}</h2>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="col-lg-3 col-sm-3">
+            <div class="card">
+                <div class="content">
+                    <div class="card-title"><a href="{{ _p.web_main }}mySpace/users.php?status={{ drh }}">{{ 'FollowedHumanResources' | get_lang }}</a></div>
+                    <div class="row">
+                        <div class="col-xs-5">
+                            <div class="icon-big icon-humanresources text-center">
+                                <i class="fa fa-user" aria-hidden="true"></i>
+                            </div>
+                        </div>
+                        <div class="col-xs-7">
+                            <div class="numbers">
+                                <h2>{{ humanresources }}</h2>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<div class="view-global">
+    <div class="panel panel-default panel-view">
+        <div class="panel-body">
+            <div class="row">
+                <div class="col-lg-3 col-sm-3">
+                    <div class="easy-donut">
+                        <div id="easypiechart-blue" class="easypiechart" data-percent="{{ total_user }}">
+                            <span class="percent">{{ total_user }}</span>
+                        </div>
+                        <div class="easypiechart-link">
+                            <a class="btn btn-default" href="{{ _p.web_main }}mySpace/users.php">
+                                {{ 'FollowedUsers' | get_lang }}
+                            </a>
+                        </div>
+                    </div>
+
+                    {% if _u.status == 1 %}
+                        <a href="{{ _p.web_main }}admin/dashboard_add_users_to_user.php?user={{ _u.id }}" class="btn btn-default btn-sm">
+                            <i class="fa fa-plus" aria-hidden="true"></i>
+                        </a>
+                    {% endif %}
+                </div>
+                <div class="col-lg-3 col-sm-3">
+                    <div class="easy-donut">
+                        <div id="easypiechart-orange" class="easypiechart" data-percent="{{ stats.courses }}">
+                            <span class="percent">{{ stats.courses }}</span>
+                        </div>
+                        <div class="easypiechart-link">
+                            <a class="btn btn-default" href="{{ _p.web_main }}mySpace/course.php">
+                                {{ 'AssignedCourses' | get_lang }}
+                            </a>
+                        </div>
+                    </div>
+                    {% if _u.status == 1 %}
+                        <a href="{{ _p.web_main }}mySpace/course.php" class="btn btn-default btn-sm">
+                            <i class="fa fa-plus" aria-hidden="true"></i>
+                        </a>
+                    {% endif %}
+                </div>
+                <div class="col-lg-3 col-sm-3">
+                    <div  class="easy-donut">
+                        <div id="easypiechart-teal" class="easypiechart" data-percent="{{ stats.assigned_courses }}">
+                            <span class="percent">{{ stats.assigned_courses }}</span>
+                        </div>
+                        <div class="easypiechart-link">
+                            <a class="btn btn-default" href="{{ _p.web_main }}mySpace/course.php?follow">{{ 'FollowedCourses' | get_lang }}</a>
+                        </div>
+                    </div>
+                    {% if _u.status == 1 %}
+                        <a href="{{ _p.web_main }}mySpace/course.php?follow" class="btn btn-default btn-sm">
+                            <i class="fa fa-plus" aria-hidden="true"></i>
+                        </a>
+                    {% endif %}
+                </div>
+                <div class="col-lg-3 col-sm-3">
+                    <div class="easy-donut">
+                        <div id="easypiechart-red" class="easypiechart" data-percent="{{ stats.session_list |length  }}">
+                            <span class="percent">{{ stats.session_list |length }}</span>
+                        </div>
+                        <div class="easypiechart-link">
+                            <a class="btn btn-default" href="{{ _p.web_main }}mySpace/session.php">{{ 'FollowedSessions' | get_lang }}</a>
+                        </div>
+                    </div>
+                    {% if _u.status == 1 %}
+                        <a href="{{ _p.web_main }}admin/dashboard_add_sessions_to_user.php?user={{ _u.id }}" class="btn btn-default btn-sm">
+                            <i class="fa fa-plus" aria-hidden="true"></i>
+                        </a>
+                    {% endif %}
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<div class="page-header">
+    <h4>
+        {{ title }}
+    </h4>
+</div>
+<div class="report-section">
+    <div class="row">
+        <div class="col-lg-3 col-sm-3">
+            <div class="item-report">
+                <div class="panel panel-default">
+                    <div class="panel-body">
+                        <div class="item-report-number">
+                            {{ report.AverageCoursePerStudent }}
+                        </div>
+                    </div>
+                </div>
+                <p>{{ 'AverageCoursePerStudent' | get_lang }}</p>
+            </div>
+        </div>
+        <div class="col-lg-3 col-sm-3">
+            <div class="item-report">
+                <div class="panel panel-default">
+                    <div class="panel-body">
+                        <div class="item-report-number">
+                            {{ report.InactivesStudents }}
+                        </div>
+                    </div>
+                </div>
+                <p>{{ 'InactivesStudents' | get_lang }}</p>
+            </div>
+        </div>
+        <div class="col-lg-3 col-sm-3">
+            <div class="item-report">
+                <div class="panel panel-default">
+                    <div class="panel-body">
+                        <div class="item-report-number">
+                            {{ report.AverageTimeSpentOnThePlatform }}
+                        </div>
+                    </div>
+                </div>
+                <p>{{ 'AverageTimeSpentOnThePlatform' | get_lang }}</p>
+            </div>
+        </div>
+        <div class="col-lg-3 col-sm-3">
+            <div class="item-report">
+                <div class="panel panel-default">
+                    <div class="panel-body">
+                        <div class="item-report-number">
+                            {{ report.AverageProgressInLearnpath }}
+                        </div>
+                    </div>
+                </div>
+                <p>{{ 'AverageProgressInLearnpath' | get_lang }}</p>
+            </div>
+        </div>
+        <div class="col-lg-3 col-sm-3">
+            <div class="item-report">
+                <div class="panel panel-default">
+                    <div class="panel-body">
+                        <div class="item-report-number">
+                            {{ report.AvgCourseScore }}
+                        </div>
+
+                    </div>
+                </div>
+                <p>{{ 'AvgCourseScore' | get_lang }}</p>
+            </div>
+        </div>
+        <div class="col-lg-3 col-sm-3">
+            <div class="item-report">
+                <div class="panel panel-default">
+                    <div class="panel-body">
+                        <div class="item-report-number">
+                            {{ report.AveragePostsInForum }}
+                        </div>
+
+                    </div>
+                </div>
+                <p> {{ 'AveragePostsInForum' | get_lang }}</p>
+            </div>
+        </div>
+        <div class="col-lg-3 col-sm-3">
+            <div class="item-report">
+                <div class="panel panel-default">
+                    <div class="panel-body">
+                        <div class="item-report-number">
+                            {{ report.AverageAssignments }}
+                        </div>
+
+                    </div>
+                </div>
+                <p> {{ 'AverageAssignments' | get_lang }}</p>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script type="text/javascript">
+    $(function() {
+        $('#easypiechart-teal').easyPieChart({
+            scaleColor: false,
+            barColor: '#1ebfae',
+            lineWidth:8,
+            trackColor: '#f2f2f2'
+        });
+    });
+
+    $(function() {
+        $('#easypiechart-orange').easyPieChart({
+            scaleColor: false,
+            barColor: '#ffb53e',
+            lineWidth:8,
+            trackColor: '#f2f2f2'
+        });
+    });
+
+    $(function() {
+        $('#easypiechart-red').easyPieChart({
+            scaleColor: false,
+            barColor: '#f9243f',
+            lineWidth:8,
+            trackColor: '#f2f2f2'
+        });
+    });
+
+    $(function() {
+        $('#easypiechart-blue').easyPieChart({
+            scaleColor: false,
+            barColor: '#30a5ff',
+            lineWidth:8,
+            trackColor: '#f2f2f2'
+        });
+    });
+
+</script>

Some files were not shown because too many files changed in this diff