angular.module("FICApp", ["ngRoute", "ngResource", "ngSanitize"]) .config(function($routeProvider, $locationProvider) { $routeProvider .when("/themes", { controller: "ThemesListController", templateUrl: "views/theme-list.html" }) .when("/themes/:themeId", { controller: "ThemeController", templateUrl: "views/theme.html" }) .when("/themes/:themeId/exercices/:exerciceId", { controller: "ExerciceController", templateUrl: "views/exercice.html" }) .when("/exercices", { controller: "AllExercicesListController", templateUrl: "views/exercice-list.html" }) .when("/exercices/:exerciceId", { controller: "ExerciceController", templateUrl: "views/exercice.html" }) .when("/", { templateUrl: "views/home.html" }); $locationProvider.html5Mode(true); }); angular.module("FICApp") .directive('autofocus', ['$timeout', function($timeout) { return { restrict: 'A', link : function($scope, $element) { $timeout(function() { $element[0].focus(); }); } } }]) .component('toast', { bindings: { date: '=', msg: '=', timeout: '=', title: '=', variant: '=', yesNo: '=', onyes: '=', onno: '=', }, controller: function($element) { if (this.timeout === 0) $element.children(0).toast({autohide: false}); else if (!this.timeout && this.timeout !== 0) $element.children(0).toast({delay: 7000}); else $element.children(0).toast({delay: this.timeout}); $element.children(0).toast('show'); this.yesFunc = function() { $element.children(0).toast('dispose'); if (this.onyes) this.onyes(); } this.noFunc = function() { $element.children(0).toast('dispose'); if (this.onno) this.onno(); } }, template: `` }); angular.module("FICApp") .factory("Version", function($resource) { return $resource("/api/version") }) .factory("Team", function($resource) { return $resource("/api/teams/:teamId", { teamId: '@id' }, { 'update': {method: 'PUT'}, }) }) .factory("Teams", function($resource) { return $resource("/api/teams.json") }) .factory("Theme", function($resource) { return $resource("/api/themes/:themeId", { themeId: '@id' }, { update: {method: 'PUT'} }); }) .factory("Themes", function($resource) { return $resource("/api/themes.json", null, { 'get': {method: 'GET'}, }) }) .factory("ThemedExercice", function($resource) { return $resource("/api/themes/:themeId/exercices/:exerciceId", { themeId: '@id', exerciceId: '@idExercice' }, { update: {method: 'PUT'} }) }) .factory("Exercice", function($resource) { return $resource("/api/exercices/:exerciceId", { exerciceId: '@id' }, { update: {method: 'PUT'}, patch: {method: 'PATCH'} }) }) .factory("ExerciceQA", function($resource) { return $resource("/api/qa/:exerciceId/:qaId", { exerciceId: '@idExercice', qaId: '@id' }, { update: {method: 'PUT'}, patch: {method: 'PATCH'} }) }); angular.module("FICApp") .filter("toColor", function() { return function(num) { num >>>= 0; var b = num & 0xFF, g = (num & 0xFF00) >>> 8, r = (num & 0xFF0000) >>> 16, a = ( (num & 0xFF000000) >>> 24 ) / 255 ; return "#" + r.toString(16) + g.toString(16) + b.toString(16); } }) .filter("cksum", function() { return function(input) { if (input == undefined) return input; var raw = atob(input).toString(16); var hex = ''; for (var i = 0; i < raw.length; i++ ) { var _hex = raw.charCodeAt(i).toString(16) hex += (_hex.length == 2 ? _hex : '0' + _hex); } return hex } }) .directive('color', function() { return { require: 'ngModel', link: function(scope, ele, attr, ctrl){ ctrl.$formatters.unshift(function(num){ num >>>= 0; var b = num & 0xFF, g = (num & 0xFF00) >>> 8, r = (num & 0xFF0000) >>> 16, a = ( (num & 0xFF000000) >>> 24 ) / 255 ; return "#" + r.toString(16) + g.toString(16) + b.toString(16); }); ctrl.$parsers.unshift(function(viewValue){ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(viewValue); return result ? ( parseInt(result[1], 16) * 256 * 256 + parseInt(result[2], 16) * 256 + parseInt(result[3], 16) ) : 0; }); } }; }) .directive('integer', function() { return { require: 'ngModel', link: function(scope, ele, attr, ctrl){ ctrl.$parsers.unshift(function(viewValue){ return parseInt(viewValue, 10); }); } }; }) .directive('float', function() { return { require: 'ngModel', link: function(scope, ele, attr, ctrl){ ctrl.$parsers.unshift(function(viewValue){ return parseFloat(viewValue, 10); }); } }; }) .run(function($rootScope, $http, $interval) { $rootScope.toasts = []; $rootScope.addToast = function(kind, title, msg, yesFunc, noFunc, tmout) { $rootScope.toasts.unshift({ variant: kind, title: title, msg: msg, timeout: tmout, yesFunc: yesFunc, noFunc: noFunc, }); } }) .controller("VersionController", function($scope, Version) { $scope.v = Version.get(); }) .controller("ThemesListController", function($scope, Theme, $location, $rootScope, $http) { $scope.themes = Theme.query(); $scope.fields = ["name", "authors", "headline"]; $scope.validateSearch = function(keyEvent) { if (keyEvent.which === 13) { var myTheme = null; $scope.themes.forEach(function(theme) { if (String(theme.name.toLowerCase()).indexOf($scope.query.toLowerCase()) >= 0) { if (myTheme === null) myTheme = theme; else myTheme = false; } }); if (myTheme) $location.url("themes/" + myTheme.id); } }; $scope.show = function(id) { $location.url("/themes/" + id); }; }) .controller("ThemeController", function($scope, Theme, $routeParams, $location, $rootScope, $http) { $scope.theme = Theme.get({ themeId: $routeParams.themeId }); $scope.fields = ["name", "urlid", "authors", "headline", "intro", "image"]; }) .controller("AllExercicesListController", function($scope, Exercice, Theme, $routeParams, $location, $rootScope, $http, $filter) { $http({ url: "/api/themes.json", method: "GET" }).then(function(response) { $scope.themes = response.data }); $scope.exercices = Exercice.query(); $scope.exercice = {}; // Array used to save fields to updates in selected exercices $scope.fields = ["title", "headline"]; $scope.validateSearch = function(keyEvent) { if (keyEvent.which === 13) { var myExercice = null; $scope.exercices.forEach(function(exercice) { if (String(exercice.title.toLowerCase()).indexOf($scope.query.toLowerCase()) >= 0) { if (myExercice === null) myExercice = exercice; else myExercice = false; } }); if (myExercice) $location.url("exercices/" + myExercice.id); } }; $scope.show = function(id) { $location.url("/exercices/" + id); }; }) .controller("ExercicesListController", function($scope, ThemedExercice, $location, $rootScope, $http) { $scope.exercices = ThemedExercice.query({ themeId: $scope.theme.id }); $scope.fields = ["title", "headline"]; $scope.show = function(id) { $location.url("/themes/" + $scope.theme.id + "/exercices/" + id); }; }) .controller("ExerciceController", function($scope, $rootScope, Exercice, ThemedExercice, $routeParams, $location, $http) { if ($routeParams.themeId && $routeParams.exerciceId == "new") { $scope.exercice = new ThemedExercice(); } else { $scope.exercice = Exercice.get({ exerciceId: $routeParams.exerciceId }); } $http({ url: "/api/themes.json", method: "GET" }).then(function(response) { $scope.themes = response.data var last_exercice = null; angular.forEach($scope.themes[$scope.exercice.id_theme].exercices, function(exercice, k) { if (last_exercice != null) { $scope.themes[$scope.exercice.id_theme].exercices[last_exercice].next = k; exercice.previous = last_exercice; } last_exercice = k; exercice.id = k; }); }); $scope.exercices = Exercice.query(); }) .controller("ExerciceQAController", function($scope, $rootScope, ExerciceQA, $routeParams, $location, $http) { $scope.queries = ExerciceQA.query({ exerciceId: $routeParams.exerciceId }); $scope.fields = ["state", "subject", "user", "creation"]; $scope.namedFields = { "state": "État", "subject": "Sujet", "content": "Description", }; $scope.states = { "ok": "OK", "orthograph": "Orthographe et grammaire", "issue-statement": "Pas compris", "issue-flag": "Problème de flag", "issue-mcq": "Problème de QCM/QCU", "issue-hint": "Problème d'indice", "issue-file": "Problème de fichier", "issue": "Problème autre", "suggest": "Suggestion", "too-hard": "Trop dur", "too-easy": "Trop facile", }; $scope.newQuery = new ExerciceQA(); $scope.query_comments = null $scope.query_selected = null $scope.showComments = function(qid) { if ($scope.query_selected == qid) { $scope.query_selected = null $scope.queries_comments = null } else { $scope.query_selected = qid $http({ url: "/api/qa/" + $routeParams.exerciceId + "/" + $scope.queries[$scope.query_selected].id + "/comments" }).then(function(response) { $scope.queries_comments = response.data }) } } $scope.newComment = {content: ""} $scope.addComment = function() { $http({ url: "/api/qa/" + $routeParams.exerciceId + "/" + $scope.queries[$scope.query_selected].id + "/comments", method: "POST", data: $scope.newComment, }).then(function(response) { $scope.newComment = {content: ""} $http({ url: "/api/qa/" + $routeParams.exerciceId + "/" + $scope.queries[$scope.query_selected].id + "/comments" }).then(function(response) { $scope.queries_comments = response.data }) }, function(response) { $scope.addToast('danger', 'An error occurs when trying to respond to QA entry:', response.data.errmsg); }) } $scope.updateQA = function(qid) { $scope.newQuery = $scope.queries[$scope.query_selected] } $scope.deleteQA = function(qid) { var myq = $scope.queries[$scope.query_selected] myq.$delete( { exerciceId: $routeParams.exerciceId, qaId: qid }, function() { $scope.queries = ExerciceQA.query({ exerciceId: $routeParams.exerciceId }); $scope.query_selected = null }, function(response) { $scope.addToast('danger', 'An error occurs when trying to delete QA query:', response.data.errmsg); } ) } $scope.solveQA = function(qid) { var myq = $scope.queries[$scope.query_selected] myq.solved = (new Date()).toISOString() myq.$update({ exerciceId: $routeParams.exerciceId, qaId: qid }) } $scope.closeQA = function(qid) { var myq = $scope.queries[$scope.query_selected] myq.closed = (new Date()).toISOString() myq.$update({ exerciceId: $routeParams.exerciceId, qaId: qid }) } $scope.saveQuery = function() { if (this.newQuery.id) { this.newQuery.$update({ exerciceId: $routeParams.exerciceId, qaId: this.newQuery.id }); } else { this.newQuery.$save({ exerciceId: $routeParams.exerciceId }, function() { //$scope.saveComment(); $scope.addToast('success', 'QA query created!'); $scope.queries = ExerciceQA.query({ exerciceId: $routeParams.exerciceId }); $scope.newQuery = new ExerciceQA(); }, function(response) { $scope.addToast('danger', 'An error occurs when trying to create QA query:', response.data.errmsg); }); } } });