From 927fb29510b752071be1889b599cecdc9d890b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 11 May 2016 13:46:51 +0200 Subject: [PATCH 1/2] MOBILE-1547 cbe: Add learning plans support --- .../competency/controllers/competencies.js | 124 ++++ .../competency/controllers/competency.js | 130 +++++ .../controllers/competencysummary.js | 69 +++ .../controllers/coursecompetencies.js | 78 +++ www/addons/competency/controllers/list.js | 66 +++ www/addons/competency/controllers/plan.js | 113 ++++ www/addons/competency/lang/en.json | 45 ++ www/addons/competency/main.js | 118 ++++ www/addons/competency/services/competency.js | 541 ++++++++++++++++++ www/addons/competency/services/handlers.js | 178 ++++++ .../competency/templates/competencies.html | 20 + .../competency/templates/competency.html | 86 +++ .../templates/competencysummary.html | 25 + .../templates/coursecompetencies.html | 66 +++ www/addons/competency/templates/list.html | 19 + www/addons/competency/templates/plan.html | 51 ++ www/core/scss/styles.scss | 7 + 17 files changed, 1736 insertions(+) create mode 100644 www/addons/competency/controllers/competencies.js create mode 100644 www/addons/competency/controllers/competency.js create mode 100644 www/addons/competency/controllers/competencysummary.js create mode 100644 www/addons/competency/controllers/coursecompetencies.js create mode 100644 www/addons/competency/controllers/list.js create mode 100644 www/addons/competency/controllers/plan.js create mode 100644 www/addons/competency/lang/en.json create mode 100644 www/addons/competency/main.js create mode 100644 www/addons/competency/services/competency.js create mode 100644 www/addons/competency/services/handlers.js create mode 100644 www/addons/competency/templates/competencies.html create mode 100644 www/addons/competency/templates/competency.html create mode 100644 www/addons/competency/templates/competencysummary.html create mode 100644 www/addons/competency/templates/coursecompetencies.html create mode 100644 www/addons/competency/templates/list.html create mode 100644 www/addons/competency/templates/plan.html diff --git a/www/addons/competency/controllers/competencies.js b/www/addons/competency/controllers/competencies.js new file mode 100644 index 00000000000..806ceb09793 --- /dev/null +++ b/www/addons/competency/controllers/competencies.js @@ -0,0 +1,124 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency') + +/** + * Controller to handle competencies of a learning plan. + * + * @module mm.addons.competency + * @ngdoc controller + * @name mmaCompetenciesListCtrl + */ +.controller('mmaCompetenciesListCtrl', function($scope, $log, $mmaCompetency, $mmUtil, $stateParams, $state, $ionicPlatform, $q, + $translate) { + + $log = $log.getInstance('mmaCompetenciesListCtrl'); + + var planId = parseInt($stateParams.pid) || false, + courseId = parseInt($stateParams.cid) || false, + competencyId = parseInt($stateParams.compid); + + function fetchCompetencies(refresh) { + var promise; + + if (planId) { + promise = $mmaCompetency.getLearningPlan(planId); + } else if (courseId){ + promise = $mmaCompetency.getCourseCompetencies(courseId); + } else { + promise = $q.reject(); + } + + return promise.then(function(response) { + if (response.competencycount <= 0) { + return $q.reject($translate.instant('mma.competency.errornocompetenciesfound')); + } + + if (planId) { + $scope.title = response.plan.name; + $scope.id = response.plan.id; + $scope.idname = 'planid'; + } else { + $scope.title = $translate.instant('mma.competency.coursecompetencies'); + $scope.id = response.courseid; + $scope.idname = 'courseid'; + } + + $scope.competencies = response.competencies; + }).catch(function(message) { + if (!refresh) { + // Some call failed, retry without using cache. + return refreshAllData(); + } + + if (message) { + $mmUtil.showErrorModal(message); + } else { + $mmUtil.showErrorModal('Error getting competencies data.'); + } + return $q.reject(); + }); + } + + $scope.gotoCompetency = function(competencyId) { + if (planId) { + // Show split view on tablet. + $state.go('site.competency', {planid: planId, competencyid: competencyId}); + } else { + $state.go('site.competency', {courseid: courseId, competencyid: competencyId}); + } + }; + + // Convenience function to refresh all the data. + function refreshAllData() { + var promise; + if (planId) { + promise = $mmaCompetency.invalidateLearningPlan(planId); + } else { + promise = $mmaCompetency.invalidateCourseCompetencies(courseId); + } + return promise.finally(function() { + return fetchCompetencies(true); + }); + } + + // Convenience function to autoload a competency if competencyId param is set. + function autoloadCompetency() { + if (competencyId) { + if ($ionicPlatform.isTablet()) { + // Search the position of the section to load. + angular.forEach($scope.competencies, function(competency, index) { + if (competency.competency.id == competencyId) { + $scope.competencyToLoad = index + 1; + } + }); + } else { + $scope.gotoCompetency(competencyId); + } + } + } + + fetchCompetencies().finally(function() { + autoloadCompetency(); + $scope.competenciesLoaded = true; + }); + + // Pull to refresh. + $scope.refreshCompetencies = function() { + refreshAllData().finally(function() { + $scope.$broadcast('scroll.refreshComplete'); + }); + }; +}); diff --git a/www/addons/competency/controllers/competency.js b/www/addons/competency/controllers/competency.js new file mode 100644 index 00000000000..bc683ef603b --- /dev/null +++ b/www/addons/competency/controllers/competency.js @@ -0,0 +1,130 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency') + +/** + * Controller to handle a competency in plan. + * + * @module mm.addons.competency + * @ngdoc controller + * @name Competency + */ +.controller('mmaCompetencyCtrl', function($scope, $log, $stateParams, $mmaCompetency, $mmUtil, $translate, $q, + mmaCompetencyReviewStatusIdle, mmaCompetencyReviewStatusInReview, mmaCompetencyReviewStatusWaitingForReview) { + + $log = $log.getInstance('mmaCompetencyCtrl'); + + var competencyId = parseInt($stateParams.competencyid), + planId = parseInt($stateParams.planid) || false, + courseId = parseInt($stateParams.courseid) || false; + + // Convenience function that fetches the event and updates the scope. + function fetchCompetency(refresh) { + + if (planId) { + promise = $mmaCompetency.getCompetencyInPlan(planId, competencyId); + } else if (courseId){ + promise = $mmaCompetency.getCompetencyInCourse(courseId, competencyId); + } else { + promise = $q.reject(); + } + + return promise.then(function(competency) { + + if (planId) { + statusName = getStatusName(competency.usercompetencysummary.usercompetency.status); + if (statusName) { + competency.usercompetencysummary.usercompetency.statusname = statusName; + } + } else { + competency.usercompetencysummary.usercompetency = competency.usercompetencysummary.usercompetencycourse; + $scope.coursemodules = competency.coursemodules; + } + + angular.forEach(competency.usercompetencysummary.evidence, function(evidence) { + if (evidence.descidentifier) { + evidence.description = $translate.instant('mma.competency.' + evidence.descidentifier, {a: evidence.desca}); + } + }); + + $scope.competency = competency.usercompetencysummary; + + }, function(message) { + if (!refresh) { + // Some call failed, retry without using cache. + return refreshAllData(); + } + + if (message) { + $mmUtil.showErrorModal(message); + } else { + $mmUtil.showErrorModal('Error getting competency data.'); + } + return $q.reject(); + }); + } + + // Convenience function to get the review status name translated + function getStatusName(status) { + var statusTranslateName; + switch (status) { + case mmaCompetencyReviewStatusIdle: + statusTranslateName = 'idle'; + break; + case mmaCompetencyReviewStatusInReview: + statusTranslateName = 'inreview'; + break; + case mmaCompetencyReviewStatusWaitingForReview: + statusTranslateName = 'waitingforreview'; + break; + default: + // We can use the current status name. + return false; + } + return $translate.instant('mma.competency.usercompetencystatus_' + statusTranslateName); + } + + // Convenience function to refresh all the data. + function refreshAllData() { + var promise; + + if (planId) { + promise = $mmaCompetency.invalidateCompetencyInPlan(planId, competencyId); + } else { + promise = $mmaCompetency.invalidateCompetencyInCourse(courseId, competencyId); + } + return promise.finally(function() { + return fetchCompetency(true); + }); + } + + // Get event. + fetchCompetency().finally(function() { + if (planId) { + $mmaCompetency.logCompetencyInPlanView(planId, competencyId); + } else { + $mmaCompetency.logCompetencyInCourseView(courseId, competencyId); + } + }).finally(function() { + $scope.competencyLoaded = true; + }); + + // Pull to refresh. + $scope.refreshCompetency = function() { + fetchCompetency(true).finally(function() { + $scope.$broadcast('scroll.refreshComplete'); + }); + }; +}); diff --git a/www/addons/competency/controllers/competencysummary.js b/www/addons/competency/controllers/competencysummary.js new file mode 100644 index 00000000000..fe3149ef52f --- /dev/null +++ b/www/addons/competency/controllers/competencysummary.js @@ -0,0 +1,69 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency') + +/** + * Controller to handle a competency summary. + * + * @module mm.addons.competency + * @ngdoc controller + * @name Competency + */ +.controller('mmaCompetencySummaryCtrl', function($scope, $log, $stateParams, $mmaCompetency, $mmUtil, $q) { + + $log = $log.getInstance('mmaCompetencySummaryCtrl'); + + var competencyId = parseInt($stateParams.competencyid); + + // Convenience function that fetches the event and updates the scope. + function fetchCompetency(refresh) { + return $mmaCompetency.getCompetencySummary(competencyId).then(function(competency) { + $scope.competency = competency; + }, function(message) { + if (!refresh) { + // Some call failed, retry without using cache. + return refreshAllData(); + } + + if (message) { + $mmUtil.showErrorModal(message); + } else { + $mmUtil.showErrorModal('Error getting competency summary data.'); + } + return $q.reject(); + }); + } + + // Convenience function to refresh all the data. + function refreshAllData() { + return $mmaCompetency.invalidateCompetencySummary(competencyId).finally(function() { + return fetchCompetency(true); + }); + } + + // Get event. + fetchCompetency().finally(function() { + $mmaCompetency.logCompetencyView(competencyId); + }).finally(function() { + $scope.competencyLoaded = true; + }); + + // Pull to refresh. + $scope.refreshCompetency = function() { + fetchCompetency(true).finally(function() { + $scope.$broadcast('scroll.refreshComplete'); + }); + }; +}); diff --git a/www/addons/competency/controllers/coursecompetencies.js b/www/addons/competency/controllers/coursecompetencies.js new file mode 100644 index 00000000000..a53857ce5d9 --- /dev/null +++ b/www/addons/competency/controllers/coursecompetencies.js @@ -0,0 +1,78 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency') + +/** + * Controller to handle course competencies. + * + * @module mm.addons.competency + * @ngdoc controller + * @name mmaCourseCompetenciesCtrl + */ +.controller('mmaCourseCompetenciesCtrl', function($scope, $log, $stateParams, $mmaCompetency, $mmUtil, $state, $ionicPlatform, $q) { + + $log = $log.getInstance('mmaCourseCompetenciesCtrl'); + + var courseId = parseInt($stateParams.courseid); + + // Convenience function that fetches the event and updates the scope. + function fetchCourseCompetencies(refresh) { + return $mmaCompetency.getCourseCompetencies(courseId).then(function(competencies) { + $scope.competencies = competencies; + }, function(message) { + if (!refresh) { + // Some call failed, retry without using cache. + return refreshAllData(); + } + + if (message) { + $mmUtil.showErrorModal(message); + } else { + $mmUtil.showErrorModal('Error getting course competencies data.'); + } + return $q.reject(); + }); + } + + $scope.gotoCompetency = function(competencyId) { + if ($ionicPlatform.isTablet()) { + // Show split view on tablet. + $state.go('site.competencies', {cid: courseId, compid: competencyId}); + } else { + $state.go('site.competency', {courseid: courseId, competencyid: competencyId}); + } + }; + + // Convenience function to refresh all the data. + function refreshAllData() { + return $mmaCompetency.invalidateCourseCompetencies(courseId).finally(function() { + return fetchCourseCompetencies(true); + }); + } + + // Get event. + fetchCourseCompetencies().finally(function() { + //$mmaCompetency.logPlanView(courseId); + }).finally(function() { + $scope.competenciesLoaded = true; + }); + + // Pull to refresh. + $scope.refreshCourseCompetencies = function() { + fetchCourseCompetencies(true).finally(function() { + $scope.$broadcast('scroll.refreshComplete'); + }); + }; +}); diff --git a/www/addons/competency/controllers/list.js b/www/addons/competency/controllers/list.js new file mode 100644 index 00000000000..2079d109c39 --- /dev/null +++ b/www/addons/competency/controllers/list.js @@ -0,0 +1,66 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency') + +/** + * Controller to handle competency learning plans. + * + * @module mm.addons.competency + * @ngdoc controller + * @name mmaLearningPlansListCtrl + */ +.controller('mmaLearningPlansListCtrl', function($scope, $log, $mmaCompetency, $mmUtil, $q) { + + $log = $log.getInstance('mmaLearningPlansListCtrl'); + + function fetchLearningPlans(refresh) { + + return $mmaCompetency.getLearningPlans().then(function(plans) { + $scope.plans = plans; + }).catch(function(message) { + if (!refresh) { + // Some call failed, retry without using cache. + return refreshAllData(); + } + + if (message) { + $mmUtil.showErrorModal(message); + } else { + $mmUtil.showErrorModal('Error getting learning plans data.'); + } + return $q.reject(); + }); + } + + // Convenience function to refresh all the data. + function refreshAllData() { + return $mmaCompetency.invalidateLearningPlans().finally(function() { + return fetchLearningPlans(true); + }); + } + + fetchLearningPlans().then(function() { + //$mmaCompetency.logPageView(currentPage); + }).finally(function() { + $scope.plansLoaded = true; + }); + + // Pull to refresh. + $scope.refreshLearningPlans = function() { + refreshAllData().finally(function() { + $scope.$broadcast('scroll.refreshComplete'); + }); + }; +}); diff --git a/www/addons/competency/controllers/plan.js b/www/addons/competency/controllers/plan.js new file mode 100644 index 00000000000..9a4801d880b --- /dev/null +++ b/www/addons/competency/controllers/plan.js @@ -0,0 +1,113 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency') + +/** + * Controller to handle a competency learning plan. + * + * @module mm.addons.competency + * @ngdoc controller + * @name mmaLearningPlanCtrl + */ +.controller('mmaLearningPlanCtrl', function($scope, $log, $stateParams, $mmaCompetency, $mmUtil, $translate, + mmaCompetencyStatusDraft, mmaCompetencyStatusActive, mmaCompetencyStatusComplete, mmaCompetencyStatusWaitingForReview, + mmaCompetencyStatusInReview, $state, $ionicPlatform, $q) { + + $log = $log.getInstance('mmaLearningPlanCtrl'); + + var planId = parseInt($stateParams.id); + + // Convenience function that fetches the event and updates the scope. + function fetchLearningPlan(refresh) { + return $mmaCompetency.getLearningPlan(planId).then(function(plan) { + var statusName; + + statusName = getStatusName(plan.plan.status); + if (statusName) { + plan.plan.statusname = statusName; + } + + $scope.plan = plan; + }, function(message) { + if (!refresh) { + // Some call failed, retry without using cache. + return refreshAllData(); + } + + if (message) { + $mmUtil.showErrorModal(message); + } else { + $mmUtil.showErrorModal('Error getting learning plan data.'); + } + return $q.reject(); + }); + } + + $scope.gotoCompetency = function(competencyId) { + if ($ionicPlatform.isTablet()) { + // Show split view on tablet. + $state.go('site.competencies', {pid: planId, compid: competencyId}); + } else { + $state.go('site.competency', {planid: planId, competencyid: competencyId}); + } + }; + + // Convenience function to get the status name translated + function getStatusName(status) { + var statusTranslateName; + switch (status) { + case mmaCompetencyStatusDraft: + statusTranslateName = 'draft'; + break; + case mmaCompetencyStatusInReview: + statusTranslateName = 'inreview'; + break; + case mmaCompetencyStatusWaitingForReview: + statusTranslateName = 'waitingforreview'; + break; + case mmaCompetencyStatusActive: + statusTranslateName = 'active'; + break; + case mmaCompetencyStatusComplete: + statusTranslateName = 'complete'; + break; + default: + // We can use the current status name. + return false; + } + return $translate.instant('mma.competency.planstatus' + statusTranslateName); + } + + // Convenience function to refresh all the data. + function refreshAllData() { + return $mmaCompetency.invalidateLearningPlan(planId).finally(function() { + return fetchLearningPlan(true); + }); + } + + // Get event. + fetchLearningPlan().finally(function() { + //$mmaCompetency.logPlanView(planId); + }).finally(function() { + $scope.planLoaded = true; + }); + + // Pull to refresh. + $scope.refreshLearningPlan = function() { + fetchLearningPlan(true).finally(function() { + $scope.$broadcast('scroll.refreshComplete'); + }); + }; +}); diff --git a/www/addons/competency/lang/en.json b/www/addons/competency/lang/en.json new file mode 100644 index 00000000000..c04c9f6b495 --- /dev/null +++ b/www/addons/competency/lang/en.json @@ -0,0 +1,45 @@ +{ + "activities": "Activities", + "competencies": "Competencies", + "coursecompetencyratingsarenotpushedtouserplans": "Competency ratings in this course do not affect learning plans.", + "coursecompetencyratingsarepushedtouserplans": "Competency ratings in this course are updated immediately in learning plans.", + "coursecompetencies": "Course competencies", + "crossreferencedcompetencies": "Cross-referenced competencies", + "duedate": "Due date", + "errornocompetenciesfound": "No competencies found", + "evidence": "Evidence", + "evidence_competencyrule": "The rule of the competency was met.", + "evidence_coursecompleted": "The course {{a}} was completed.", + "evidence_coursemodulecompleted": "The activity {{a}} was completed.", + "evidence_courserestored": "The rating was restored along with the course {{a}}.", + "evidence_evidenceofpriorlearninglinked": "The evidence of prior learning {{a}} was linked.", + "evidence_evidenceofpriorlearningunlinked": "The evidence of prior learning {{a}} was unlinked.", + "evidence_manualoverride": "The competency rating was manually set.", + "evidence_manualoverrideincourse": "The competency rating was manually set in the course {{a}}.", + "evidence_manualoverrideinplan": "The competency rating was manually set in the learning plan {{a}}.", + "learningplancompetencies": "Learning plan competencies", + "noactivities": "No activities", + "mylearningplans": "My learning plans", + "nocrossreferencedcompetencies": "No other competencies have been cross-referenced to this competency.", + "nocompetencies": "No competencies", + "noplanswerecreated": "No learning plans were created.", + "noevidence": "No evidence", + "path": "Path:", + "planstatusactive": "Active", + "planstatuscomplete": "Complete", + "planstatusdraft": "Draft", + "planstatusinreview": "In review", + "planstatuswaitingforreview": "Waiting for review", + "proficient": "Proficient", + "progress": "Progress", + "rating": "Rating", + "reviewstatus": "Review status", + "status": "Status", + "template": "Learning plan template", + "usercompetencystatus_idle": "Idle", + "usercompetencystatus_inreview": "In review", + "usercompetencystatus_waitingforreview": "Waiting for review", + "userplans": "Learning plans", + "xcompetenciesproficientoutofy": "{{x}} out of {{y}} competencies are proficient", + "xcompetenciesproficientoutofyincourse": "You are proficient in {{x}} out of {{y}} competencies in this course." +} diff --git a/www/addons/competency/main.js b/www/addons/competency/main.js new file mode 100644 index 00000000000..63244da4a28 --- /dev/null +++ b/www/addons/competency/main.js @@ -0,0 +1,118 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency', []) + +.constant('mmaCompetencyPriority', 900) +.constant('mmaCourseCompetenciesPriority', 700) +.constant('mmaCompetencyStatusDraft', 0) +.constant('mmaCompetencyStatusActive', 1) +.constant('mmaCompetencyStatusComplete', 2) +.constant('mmaCompetencyStatusWaitingForReview', 3) +.constant('mmaCompetencyStatusInReview', 4) +.constant('mmaCompetencyReviewStatusIdle', 0) +.constant('mmaCompetencyReviewStatusWaitingForReview', 1) +.constant('mmaCompetencyReviewStatusInReview', 2) + +.config(function($stateProvider, $mmSideMenuDelegateProvider, $mmCoursesDelegateProvider, mmaCompetencyPriority, + mmaCourseCompetenciesPriority) { + + $stateProvider + .state('site.learningplans', { + url: '/learningplans', + views: { + 'site': { + controller: 'mmaLearningPlansListCtrl', + templateUrl: 'addons/competency/templates/list.html' + } + } + }) + + .state('site.learningplan', { + url: '/learningplan', + params: { + id: null + }, + views: { + 'site': { + controller: 'mmaLearningPlanCtrl', + templateUrl: 'addons/competency/templates/plan.html' + } + } + }) + + .state('site.competencies', { + url: '/competencies', + params: { + pid: null, + cid: null, + compid: null + }, + views: { + 'site': { + controller: 'mmaCompetenciesListCtrl', + templateUrl: 'addons/competency/templates/competencies.html' + } + } + }) + + .state('site.competency', { + url: '/competency', + params: { + planid: null, + courseid: null, + competencyid: null + }, + views: { + 'site': { + controller: 'mmaCompetencyCtrl', + templateUrl: 'addons/competency/templates/competency.html' + } + } + }) + + .state('site.coursecompetencies', { + url: '/coursecompetencies', + params: { + courseid: null + }, + views: { + 'site': { + controller: 'mmaCourseCompetenciesCtrl', + templateUrl: 'addons/competency/templates/coursecompetencies.html' + } + } + }) + + .state('site.competencysummary', { + url: '/competencysummary', + params: { + competencyid: null + }, + views: { + 'site': { + controller: 'mmaCompetencySummaryCtrl', + templateUrl: 'addons/competency/templates/competencysummary.html' + } + } + }); + + + // Register side menu addon. + $mmSideMenuDelegateProvider.registerNavHandler('mmaCompetency', '$mmaCompetencyHandlers.sideMenuNav', mmaCompetencyPriority); + + // Register courses handler. + $mmCoursesDelegateProvider.registerNavHandler('mmaCompetency', '$mmaCompetencyHandlers.coursesNav', + mmaCourseCompetenciesPriority); +}); \ No newline at end of file diff --git a/www/addons/competency/services/competency.js b/www/addons/competency/services/competency.js new file mode 100644 index 00000000000..e433cc5b23c --- /dev/null +++ b/www/addons/competency/services/competency.js @@ -0,0 +1,541 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency') + +/** + * Service to handle caompetency learning plans. + * + * @module mm.addons.competency + * @ngdoc service + * @name $mmaCompetency + */ +.factory('$mmaCompetency', function($log, $mmSite, $mmSitesManager, $q) { + + $log = $log.getInstance('$mmaCompetency'); + + var self = {}; + + /** + * Get cache key for user learning plans data WS calls. + * + * @param {Number} userId User ID. + * @return {String} Cache key. + */ + function getLearningPlansCacheKey(userId) { + return 'mmaCompetency:userplans:' + userId; + } + + /** + * Get cache key for learning plan data WS calls. + * + * @param {Number} planId Plan ID. + * @return {String} Cache key. + */ + function getLearningPlanCacheKey(planId) { + return 'mmaCompetency:learningplan:' + planId; + } + + /** + * Get cache key for competency in plan data WS calls. + * + * @param {Number} planId Plan ID. + * @param {Number} competencyId Competency ID. + * @return {String} Cache key. + */ + function getCompetencyInPlanCacheKey(planId, competencyId) { + return 'mmaCompetency:plancompetency:' + planId + ':' + competencyId; + } + + /** + * Get cache key for competency in course data WS calls. + * + * @param {Number} courseId Course ID. + * @param {Number} competencyId Competency ID. + * @param {Number} userId User ID. + * @return {String} Cache key. + */ + function getCompetencyInCourseCacheKey(courseId, competencyId, userId) { + return 'mmaCompetency:coursecompetency:' + userId + ':' + courseId + ':' + competencyId; + } + + /** + * Get cache key for competency summary data WS calls. + * + * @param {Number} competencyId Competency ID. + * @param {Number} userId User ID. + * @return {String} Cache key. + */ + function getCompetencySummaryCacheKey(competencyId, userId) { + return 'mmaCompetency:competencysummary:' + userId + ':' + competencyId; + } + + /** + * Get cache key for course competencies data WS calls. + * + * @param {Number} courseId Course ID. + * @return {String} Cache key. + */ + function getCourseCompetenciesCacheKey(courseId) { + return 'mmaCompetency:coursecompetencies:' + courseId; + } + + /** + * Check if competency learning plans WS is available. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#isPluginEnabled + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Boolean} True if competency learning plans WS is available, false otherwise. + */ + self.isPluginEnabled = function(siteId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.wsAvailable('core_competency_list_course_competencies') && + site.wsAvailable('tool_lp_data_for_plans_page') && + self.getLearningPlans(false, siteId); + }); + }; + + /** + * Returns whether competencies are enabled. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#isPluginForCourseEnabled + * @param {Number} courseId Course ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Boolean} + */ + self.isPluginForCourseEnabled = function(courseId, siteId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + if (!site.isLoggedIn()) { + return false; + } + if(!self.isPluginEnabled(siteId)) { + return false; + } + if (!self.getCourseCompetencies(courseId, siteId)) { + return false; + } + return true; + }); + }; + + /** + * Get plans for a certain user. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#getLearningPlans + * @param {Number} [userId] ID of the user. If not defined, current user. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise to be resolved when the plans are retrieved. + */ + self.getLearningPlans = function(userId, siteId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + + $log.debug('Get plans for user ' + userId); + + var params = { + userid: userId + }, + preSets = { + cacheKey: getLearningPlansCacheKey(userId) + }; + + return site.read('tool_lp_data_for_plans_page', params, preSets).then(function(response) { + if (response.plans) { + return response.plans; + } + return $q.reject(); + }); + }); + }; + + /** + * Get a certain plan. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#getLearningPlan + * @param {Number} planId ID of the plan. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise to be resolved when the plans are retrieved. + */ + self.getLearningPlan = function(planId, siteId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + + $log.debug('Get plan ' + planId); + + var params = { + planid: planId + }, + preSets = { + cacheKey: getLearningPlanCacheKey(planId) + }; + + return site.read('tool_lp_data_for_plan_page', params, preSets).then(function(response) { + if (response.plan) { + return response; + } + return $q.reject(); + }); + }); + }; + + /** + * Get a certain competency in a plan. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#getCompetencyInPlan + * @param {Number} planId ID of the plan. + * @param {Number} competencyId ID of the competency. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise to be resolved when the plans are retrieved. + */ + self.getCompetencyInPlan = function(planId, competencyId, siteId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + + $log.debug('Get competency ' + competencyId + ' in plan ' + planId); + + var params = { + planid: planId, + competencyid: competencyId + }, + preSets = { + cacheKey: getCompetencyInPlanCacheKey(planId, competencyId) + }; + + return site.read('tool_lp_data_for_user_competency_summary_in_plan', params, preSets).then(function(response) { + if (response.usercompetencysummary) { + return response; + } + return $q.reject(); + }); + }); + }; + + /** + * Get a certain competency in a course. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#getCompetencyInCourse + * @param {Number} courseId ID of the course. + * @param {Number} competencyId ID of the competency. + * @param {Number} [userId] ID of the user. If not defined, current user. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise to be resolved when the plans are retrieved. + */ + self.getCompetencyInCourse = function(courseId, competencyId, userId, siteId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + + $log.debug('Get competency ' + competencyId + ' in course ' + courseId); + + var params = { + courseid: courseId, + competencyid: competencyId, + userid: userId + }, + preSets = { + cacheKey: getCompetencyInCourseCacheKey(courseId, competencyId, userId) + }; + + return site.read('tool_lp_data_for_user_competency_summary_in_course', params, preSets).then(function(response) { + if (response.usercompetencysummary) { + return response; + } + return $q.reject(); + }); + }); + }; + + /** + * Get a certain competency summary. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#getCompetencySummary + * @param {Number} competencyId ID of the competency. + * @param {Number} [userId] ID of the user. If not defined, current user. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise to be resolved when the plans are retrieved. + */ + self.getCompetencySummary = function(competencyId, userId, siteId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + + $log.debug('Get competency ' + competencyId + ' summary for user' + userId); + + var params = { + competencyid: competencyId, + userid: userId + }, + preSets = { + cacheKey: getCompetencySummaryCacheKey(competencyId, userId) + }; + + return site.read('tool_lp_data_for_user_competency_summary', params, preSets).then(function(response) { + if (response.competency) { + return response.competency; + } + return $q.reject(); + }); + }); + }; + + /** + * Get a certain competency summary. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#getCourseCompetencies + * @param {Number} [courseId] ID of the course. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise to be resolved when the plans are retrieved. + */ + self.getCourseCompetencies = function(courseId, siteId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + + $log.debug('Get course competencies for course ' + courseId); + + var params = { + courseid: courseId + }, + preSets = { + cacheKey: getCourseCompetenciesCacheKey(courseId) + }; + return site.read('tool_lp_data_for_course_competencies_page', params, preSets).then(function(response) { + if (response.competencies) { + return response; + } + return $q.reject(); + }); + }); + }; + + /** + * Invalidates User Learning Plans data. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#invalidateLearningPlans + * @param {Number} [userId] ID of the user. If not defined, current user. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateLearningPlans = function(userId, siteId) { + siteId = siteId || $mmSite.getId(); + return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + return site.invalidateWsCacheForKey(getLearningPlansCacheKey(userId)); + }); + }; + + /** + * Invalidates Learning Plan data. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#invalidateLearningPlan + * @param {Number} planId ID of the plan. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateLearningPlan = function(planId, siteId) { + siteId = siteId || $mmSite.getId(); + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKey(getLearningPlanCacheKey(planId)); + }); + }; + + /** + * Invalidates Competency in Plan data. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#invalidateCompetencyInPlan + * @param {Number} planId ID of the plan. + * @param {Number} competencyId ID of the competency. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateCompetencyInPlan = function(planId, competencyId, siteId) { + siteId = siteId || $mmSite.getId(); + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKey(getCompetencyInPlanCacheKey(planId, competencyId)); + }); + }; + + /** + * Invalidates Competency in Course data. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#invalidateCompetencyInCourse + * @param {Number} courseId ID of the course. + * @param {Number} competencyId ID of the competency. + * @param {Number} [userId] ID of the user. If not defined, current user. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateCompetencyInCourse = function(courseId, competencyId, userId, siteId) { + siteId = siteId || $mmSite.getId(); + return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + return site.invalidateWsCacheForKey(getCompetencyInCourseCacheKey(courseId, competencyId, userId)); + }); + }; + + + /** + * Invalidates Competency Summary data. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#invalidateCompetencySummary + * @param {Number} competencyId ID of the competency. + * @param {Number} [userId] ID of the user. If not defined, current user. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateCompetencySummary = function(competencyId, userId, siteId) { + siteId = siteId || $mmSite.getId(); + return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + return site.invalidateWsCacheForKey(getCompetencySummaryCacheKey(competencyId, userId)); + }); + }; + + /** + * Invalidates Course Competencies data. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#invalidateCourseCompetencies + * @param {Number} courseId ID of the course. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateCourseCompetencies = function(courseId, siteId) { + siteId = siteId || $mmSite.getId(); + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKey(getCourseCompetenciesCacheKey(courseId)); + }); + }; + + /** + * Report the competency as being viewed in plan. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#logCompetencyInPlanView + * @param {Number} planId ID of the plan. + * @param {Number} competencyId ID of the competency. + * @param {String} [userId] User ID. If not defined, current user. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the WS call is successful. + */ + self.logCompetencyInPlanView = function(planId, competencyId, userId, siteId) { + if (planId && competencyId) { + siteId = siteId || $mmSite.getId(); + userId = userId || $mmSite.getUserId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + planid: planId, + competencyid: competencyId, + userid: userId + }; + return site.write('core_competency_user_competency_viewed_in_plan', params); + }); + } + return $q.reject(); + }; + + /** + * Report the competency as being viewed in course. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#logCompetencyInCourseView + * @param {Number} courseId ID of the course. + * @param {Number} competencyId ID of the competency. + * @param {String} [userId] User ID. If not defined, current user. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the WS call is successful. + */ + self.logCompetencyInCourseView = function(courseId, competencyId, userId, siteId) { + if (courseId && competencyId) { + siteId = siteId || $mmSite.getId(); + userId = userId || $mmSite.getUserId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + courseid: courseId, + competencyid: competencyId, + userid: userId + }; + return site.write('core_competency_user_competency_viewed_in_course', params); + }); + } + return $q.reject(); + }; + + /** + * Report the competency as being viewed. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetency#logCompetencyView + * @param {Number} competencyId ID of the competency. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the WS call is successful. + */ + self.logCompetencyView = function(competencyId, siteId) { + if (competencyId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + id: competencyId, + }; + return site.write('core_competency_competency_viewed', params); + }); + } + return $q.reject(); + }; + + return self; +}); diff --git a/www/addons/competency/services/handlers.js b/www/addons/competency/services/handlers.js new file mode 100644 index 00000000000..7c874584da0 --- /dev/null +++ b/www/addons/competency/services/handlers.js @@ -0,0 +1,178 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency') + +/** + * Competency handlers factory. + * + * This factory holds the different handlers used for delegates. + * + * @module mm.addons.competency + * @ngdoc service + * @name $mmaCompetencyHandlers + */ +.factory('$mmaCompetencyHandlers', function($log, $mmaCompetency, mmCoursesAccessMethods) { + $log = $log.getInstance('$mmaCompetencyHandlers'); + + var self = {}, + coursesNavEnabledCache = {}; + + /** + * Clear courses nav cache. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetencyHandlers#clearCoursesNavCache + */ + self.clearCoursesNavCache = function() { + coursesNavEnabledCache = {}; + }; + + /** + * Side menu nav handler. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetencyHandlers#sideMenuNav + */ + self.sideMenuNav = function() { + + var self = {}; + + /** + * Check if handler is enabled. + * + * @param {String} siteId Site ID. + * @return {Promise} Promise resolved with true if enabled. + */ + self.isEnabled = function(siteId) { + return $mmaCompetency.isPluginEnabled(siteId).then(function(enabled) { + if (!enabled) { + return false; + } + + // Check the user has at least one learn plan available. + return $mmaCompetency.getLearningPlans(false, siteId).then(function(plans) { + return plans.length > 0; + }); + }); + }; + + /** + * Get the controller. + * + * @return {Object} Controller. + */ + self.getController = function() { + + /** + * Side menu nav handler controller. + * + * @module mm.addons.competency + * @ngdoc controller + * @name $mmaCompetencyHandlers#sideMenuNav:controller + */ + return function($scope) { + $scope.icon = 'ion-map'; + $scope.title = 'mma.competency.mylearningplans'; + $scope.state = 'site.learningplans'; + $scope.class = 'mma-competency-handler'; + }; + }; + + return self; + }; + + /** + * Course nav handler. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetencyHandlers#coursesNav + */ + self.coursesNav = function() { + + var self = {}; + + /** + * Check if handler is enabled. + * + * @return {Boolean} True if handler is enabled, false otherwise. + */ + self.isEnabled = function() { + return $mmaCompetency.isPluginEnabled(); + }; + + /** + * Check if handler is enabled for this course. + * + * @param {Number} courseId Course ID. + * @param {Object} accessData Type of access to the course: default, guest, ... + * @return {Boolean} True if handler is enabled, false otherwise. + */ + self.isEnabledForCourse = function(courseId, accessData) { + if (accessData && accessData.type == mmCoursesAccessMethods.guest) { + return false; // Not enabled for guests. + } + if (typeof coursesNavEnabledCache[courseId] != 'undefined') { + return coursesNavEnabledCache[courseId]; + } + return $mmaCompetency.isPluginForCourseEnabled(courseId).then(function(enabled) { + coursesNavEnabledCache[courseId] = enabled; + return enabled; + }); + }; + + /** + * Get the controller. + * + * @param {Number} courseId Course ID. + * @return {Object} Controller. + */ + self.getController = function(courseId) { + + /** + * Courses nav handler controller. + * + * @module mm.addons.competency + * @ngdoc controller + * @name $mmaCompetencyHandlers#coursesNav:controller + */ + return function($scope, $state) { + $scope.icon = 'ion-ribbon-a'; + $scope.title = 'mma.competency.competencies'; + $scope.class = 'mma-competency-handler'; + $scope.action = function($event, course) { + $event.preventDefault(); + $event.stopPropagation(); + $state.go('site.coursecompetencies', { + courseid: course.id + }); + }; + }; + }; + + return self; + }; + + return self; +}) + +.run(function($mmaCompetencyHandlers, $mmEvents, mmCoreEventLogout, mmCoursesEventMyCoursesRefreshed) { + $mmEvents.on(mmCoreEventLogout, function() { + $mmaCompetencyHandlers.clearCoursesNavCache(); + }); + $mmEvents.on(mmCoursesEventMyCoursesRefreshed, $mmaCompetencyHandlers.clearCoursesNavCache); +}); diff --git a/www/addons/competency/templates/competencies.html b/www/addons/competency/templates/competencies.html new file mode 100644 index 00000000000..b02c59f55f9 --- /dev/null +++ b/www/addons/competency/templates/competencies.html @@ -0,0 +1,20 @@ + + {{ title }} + + + + + + + + + + \ No newline at end of file diff --git a/www/addons/competency/templates/competency.html b/www/addons/competency/templates/competency.html new file mode 100644 index 00000000000..d6a1f0eaa4e --- /dev/null +++ b/www/addons/competency/templates/competency.html @@ -0,0 +1,86 @@ + + {{ competency.competency.competency.shortname }} {{ competency.competency.competency.idnumber }} + + + + + +
+
    +
  • + {{ competency.competency.competency.description }} +
  • +
  • + {{ 'mma.competency.path' | translate }} + {{ competency.competency.comppath.framework.name }} + +  / {{ ancestor.name }} + +
  • +
  • + {{ 'mma.competency.crossreferencedcompetencies' | translate }}: +
    {{ 'mma.competency.nocrossreferencedcompetencies' | translate }}
    + +
  • +
  • + {{ 'mma.competency.activities' | translate }}: + + {{ 'mma.competency.noactivities' | translate }} + + +
  • +
  • + {{ 'mma.competency.reviewstatus' | translate }}: + {{ competency.usercompetency.statusname }} +
  • +
  • + {{ 'mma.competency.proficient' | translate }}: + + {{ 'mm.core.yes' | translate }} + + + {{ 'mm.core.no' | translate }} + +
  • +
  • + {{ 'mma.competency.rating' | translate }}: + {{ competency.usercompetency.gradename }} +
  • +
+
+ + +
+
+
\ No newline at end of file diff --git a/www/addons/competency/templates/competencysummary.html b/www/addons/competency/templates/competencysummary.html new file mode 100644 index 00000000000..a77aeabeb6e --- /dev/null +++ b/www/addons/competency/templates/competencysummary.html @@ -0,0 +1,25 @@ + + {{ competency.competency.shortname }} {{ competency.competency.idnumber }} + + + + + +
+
    +
  • + {{ competency.competency.description }} +
  • +
  • + {{ 'mma.competency.path' | translate }} + {{ competency.comppath.framework.name }} + +  / {{ ancestor.name }} + +
  • +
+
+
+
+
\ No newline at end of file diff --git a/www/addons/competency/templates/coursecompetencies.html b/www/addons/competency/templates/coursecompetencies.html new file mode 100644 index 00000000000..492da0f7dad --- /dev/null +++ b/www/addons/competency/templates/coursecompetencies.html @@ -0,0 +1,66 @@ + + {{ 'mma.competency.coursecompetencies' | translate }} + + + + + +
+
    +
  • + {{ 'mma.competency.coursecompetencyratingsarepushedtouserplans' | translate }} +
  • +
  • + {{ 'mma.competency.coursecompetencyratingsarenotpushedtouserplans' | translate }} +
  • +
  • + {{ 'mma.competency.progress' | translate }}: + {{ 'mma.competency.xcompetenciesproficientoutofyincourse' | translate:{x: competencies.statistics.proficientcompetencycount, y: competencies.statistics.competencycount} }} ({{ competencies.statistics.proficientcompetencypercentageformatted }}%) + +
  • +
+
+ +
+

{{ 'mma.competency.competencies' | translate }}

+ + {{ 'mma.competency.nocompetencies' | translate }} + + +
+ + {{competency.competency.shortname}} {{competency.competency.idnumber}} + {{ competency.usercompetencycourse.gradename }}
+
+
+
+ {{ competency.competency.description }} +
+
+ {{ 'mma.competency.path' | translate }} + {{ competency.comppath.framework.name }} + +  / {{ ancestor.name }} + +
+
+ {{ 'mma.competency.activities' | translate }}: + + {{ 'mma.competency.noactivities' | translate }} + + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/www/addons/competency/templates/list.html b/www/addons/competency/templates/list.html new file mode 100644 index 00000000000..00c7905495c --- /dev/null +++ b/www/addons/competency/templates/list.html @@ -0,0 +1,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/www/addons/competency/templates/plan.html b/www/addons/competency/templates/plan.html new file mode 100644 index 00000000000..76d027e93c4 --- /dev/null +++ b/www/addons/competency/templates/plan.html @@ -0,0 +1,51 @@ + + {{plan.plan.name}} + + + + + +
+
    +
  • + {{ competency.usercompetencysummary.competency.competency.description }} +
  • +
  • + {{ 'mma.competency.status' | translate }}: + {{ plan.plan.statusname }} +
  • +
  • + {{ 'mma.competency.duedate' | translate }}: + {{ plan.plan.duedate | mmToLocaleString }} +
  • +
  • + {{ 'mma.competency.template' | translate }}: + {{ plan.plan.template.shortname }} +
  • +
  • + {{ 'mma.competency.progress' | translate }}: + {{ 'mma.competency.xcompetenciesproficientoutofy' | translate:{x: plan.proficientcompetencycount, y: plan.competencycount} }} ({{ plan.proficientcompetencypercentageformatted }}%) + +
  • +
+
+ + +
+
+
\ No newline at end of file diff --git a/www/core/scss/styles.scss b/www/core/scss/styles.scss index fbc2bf00e96..811c64cab31 100644 --- a/www/core/scss/styles.scss +++ b/www/core/scss/styles.scss @@ -369,6 +369,13 @@ p.mm-warning { border-radius: 50%; } +.badge.badge-inline { + display: inline; + position: relative; + top: initial; + right: initial; +} + // Timer. mm-timer { display: block; From 3550901619619574a8517dd16c18bf851654e298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 12 May 2016 16:09:00 +0200 Subject: [PATCH 2/2] MOBILE-1547 cbe: Add course competencies support --- .../competency/controllers/competencies.js | 23 ++-- .../competency/controllers/competency.js | 48 +++---- .../controllers/competencysummary.js | 20 +-- .../controllers/coursecompetencies.js | 29 ++-- www/addons/competency/controllers/plan.js | 35 ++--- .../controllers/{list.js => planlist.js} | 21 +-- www/addons/competency/lang/en.json | 2 + www/addons/competency/main.js | 26 ++-- www/addons/competency/services/competency.js | 60 ++++---- www/addons/competency/services/handlers.js | 129 +++++++++++++++++- www/addons/competency/services/helper.js | 45 ++++++ .../competency/templates/competency.html | 9 +- .../templates/coursecompetencies.html | 19 ++- www/addons/competency/templates/plan.html | 5 + .../templates/{list.html => planlist.html} | 0 www/addons/notes/services/handlers.js | 2 +- www/core/lib/util.js | 2 +- 17 files changed, 331 insertions(+), 144 deletions(-) rename www/addons/competency/controllers/{list.js => planlist.js} (68%) create mode 100644 www/addons/competency/services/helper.js rename www/addons/competency/templates/{list.html => planlist.html} (100%) diff --git a/www/addons/competency/controllers/competencies.js b/www/addons/competency/controllers/competencies.js index 806ceb09793..d7844588020 100644 --- a/www/addons/competency/controllers/competencies.js +++ b/www/addons/competency/controllers/competencies.js @@ -21,16 +21,15 @@ angular.module('mm.addons.competency') * @ngdoc controller * @name mmaCompetenciesListCtrl */ -.controller('mmaCompetenciesListCtrl', function($scope, $log, $mmaCompetency, $mmUtil, $stateParams, $state, $ionicPlatform, $q, - $translate) { - - $log = $log.getInstance('mmaCompetenciesListCtrl'); +.controller('mmaCompetenciesListCtrl', function($scope, $mmaCompetency, $mmUtil, $stateParams, $state, $ionicPlatform, $q, + $translate, $mmaCompetencyHelper) { var planId = parseInt($stateParams.pid) || false, courseId = parseInt($stateParams.cid) || false, - competencyId = parseInt($stateParams.compid); + competencyId = parseInt($stateParams.compid), + userId = parseInt($stateParams.uid) || false; - function fetchCompetencies(refresh) { + function fetchCompetencies() { var promise; if (planId) { @@ -50,6 +49,7 @@ angular.module('mm.addons.competency') $scope.title = response.plan.name; $scope.id = response.plan.id; $scope.idname = 'planid'; + userId = response.plan.userid; } else { $scope.title = $translate.instant('mma.competency.coursecompetencies'); $scope.id = response.courseid; @@ -58,11 +58,6 @@ angular.module('mm.addons.competency') $scope.competencies = response.competencies; }).catch(function(message) { - if (!refresh) { - // Some call failed, retry without using cache. - return refreshAllData(); - } - if (message) { $mmUtil.showErrorModal(message); } else { @@ -77,7 +72,7 @@ angular.module('mm.addons.competency') // Show split view on tablet. $state.go('site.competency', {planid: planId, competencyid: competencyId}); } else { - $state.go('site.competency', {courseid: courseId, competencyid: competencyId}); + $state.go('site.competency', {courseid: courseId, competencyid: competencyId, userid: userId}); } }; @@ -85,12 +80,12 @@ angular.module('mm.addons.competency') function refreshAllData() { var promise; if (planId) { - promise = $mmaCompetency.invalidateLearningPlan(planId); + promise = $mmaCompetency.invalidateLearningPlan(planId); } else { promise = $mmaCompetency.invalidateCourseCompetencies(courseId); } return promise.finally(function() { - return fetchCompetencies(true); + return fetchCompetencies(); }); } diff --git a/www/addons/competency/controllers/competency.js b/www/addons/competency/controllers/competency.js index bc683ef603b..2c50d41fd87 100644 --- a/www/addons/competency/controllers/competency.js +++ b/www/addons/competency/controllers/competency.js @@ -19,24 +19,25 @@ angular.module('mm.addons.competency') * * @module mm.addons.competency * @ngdoc controller - * @name Competency + * @name mmaCompetencyCtrl */ -.controller('mmaCompetencyCtrl', function($scope, $log, $stateParams, $mmaCompetency, $mmUtil, $translate, $q, +.controller('mmaCompetencyCtrl', function($scope, $stateParams, $mmaCompetency, $mmUtil, $translate, $q, $mmSite, mmaCompetencyReviewStatusIdle, mmaCompetencyReviewStatusInReview, mmaCompetencyReviewStatusWaitingForReview) { - $log = $log.getInstance('mmaCompetencyCtrl'); - var competencyId = parseInt($stateParams.competencyid), planId = parseInt($stateParams.planid) || false, - courseId = parseInt($stateParams.courseid) || false; + courseId = parseInt($stateParams.courseid) || false, + userId = parseInt($stateParams.userid) || false, + planStatus = false; // Convenience function that fetches the event and updates the scope. - function fetchCompetency(refresh) { + function fetchCompetency() { if (planId) { + planStatus = false; promise = $mmaCompetency.getCompetencyInPlan(planId, competencyId); } else if (courseId){ - promise = $mmaCompetency.getCompetencyInCourse(courseId, competencyId); + promise = $mmaCompetency.getCompetencyInCourse(courseId, competencyId, userId); } else { promise = $q.reject(); } @@ -44,15 +45,22 @@ angular.module('mm.addons.competency') return promise.then(function(competency) { if (planId) { - statusName = getStatusName(competency.usercompetencysummary.usercompetency.status); - if (statusName) { - competency.usercompetencysummary.usercompetency.statusname = statusName; - } + planStatus = competency.plan.status; + competency.usercompetencysummary.usercompetency.statusname = getStatusName(competency.usercompetencysummary.usercompetency.status); } else { competency.usercompetencysummary.usercompetency = competency.usercompetencysummary.usercompetencycourse; $scope.coursemodules = competency.coursemodules; } + if (competency.usercompetencysummary.user.id != $mmSite.getUserId()) { + competency.usercompetencysummary.user.profileimageurl = competency.usercompetencysummary.user.profileimageurl + || true; + + // Get the user profile image from the returned object. + $scope.user = competency.usercompetencysummary.user; + console.log($scope.user); + } + angular.forEach(competency.usercompetencysummary.evidence, function(evidence) { if (evidence.descidentifier) { evidence.description = $translate.instant('mma.competency.' + evidence.descidentifier, {a: evidence.desca}); @@ -62,11 +70,6 @@ angular.module('mm.addons.competency') $scope.competency = competency.usercompetencysummary; }, function(message) { - if (!refresh) { - // Some call failed, retry without using cache. - return refreshAllData(); - } - if (message) { $mmUtil.showErrorModal(message); } else { @@ -91,7 +94,7 @@ angular.module('mm.addons.competency') break; default: // We can use the current status name. - return false; + return status; } return $translate.instant('mma.competency.usercompetencystatus_' + statusTranslateName); } @@ -106,16 +109,15 @@ angular.module('mm.addons.competency') promise = $mmaCompetency.invalidateCompetencyInCourse(courseId, competencyId); } return promise.finally(function() { - return fetchCompetency(true); + return fetchCompetency(); }); } - // Get event. - fetchCompetency().finally(function() { + fetchCompetency().then(function() { if (planId) { - $mmaCompetency.logCompetencyInPlanView(planId, competencyId); + $mmaCompetency.logCompetencyInPlanView(planId, competencyId, planStatus, userId); } else { - $mmaCompetency.logCompetencyInCourseView(courseId, competencyId); + $mmaCompetency.logCompetencyInCourseView(courseId, competencyId, userId); } }).finally(function() { $scope.competencyLoaded = true; @@ -123,7 +125,7 @@ angular.module('mm.addons.competency') // Pull to refresh. $scope.refreshCompetency = function() { - fetchCompetency(true).finally(function() { + refreshAllData().finally(function() { $scope.$broadcast('scroll.refreshComplete'); }); }; diff --git a/www/addons/competency/controllers/competencysummary.js b/www/addons/competency/controllers/competencysummary.js index fe3149ef52f..606f267831d 100644 --- a/www/addons/competency/controllers/competencysummary.js +++ b/www/addons/competency/controllers/competencysummary.js @@ -19,24 +19,17 @@ angular.module('mm.addons.competency') * * @module mm.addons.competency * @ngdoc controller - * @name Competency + * @name mmaCompetencySummaryCtrl */ -.controller('mmaCompetencySummaryCtrl', function($scope, $log, $stateParams, $mmaCompetency, $mmUtil, $q) { - - $log = $log.getInstance('mmaCompetencySummaryCtrl'); +.controller('mmaCompetencySummaryCtrl', function($scope, $stateParams, $mmaCompetency, $mmUtil, $q) { var competencyId = parseInt($stateParams.competencyid); // Convenience function that fetches the event and updates the scope. - function fetchCompetency(refresh) { + function fetchCompetency() { return $mmaCompetency.getCompetencySummary(competencyId).then(function(competency) { $scope.competency = competency; }, function(message) { - if (!refresh) { - // Some call failed, retry without using cache. - return refreshAllData(); - } - if (message) { $mmUtil.showErrorModal(message); } else { @@ -49,12 +42,11 @@ angular.module('mm.addons.competency') // Convenience function to refresh all the data. function refreshAllData() { return $mmaCompetency.invalidateCompetencySummary(competencyId).finally(function() { - return fetchCompetency(true); + return fetchCompetency(); }); } - // Get event. - fetchCompetency().finally(function() { + fetchCompetency().then(function() { $mmaCompetency.logCompetencyView(competencyId); }).finally(function() { $scope.competencyLoaded = true; @@ -62,7 +54,7 @@ angular.module('mm.addons.competency') // Pull to refresh. $scope.refreshCompetency = function() { - fetchCompetency(true).finally(function() { + refreshAllData().finally(function() { $scope.$broadcast('scroll.refreshComplete'); }); }; diff --git a/www/addons/competency/controllers/coursecompetencies.js b/www/addons/competency/controllers/coursecompetencies.js index a53857ce5d9..70ea2b502c2 100644 --- a/www/addons/competency/controllers/coursecompetencies.js +++ b/www/addons/competency/controllers/coursecompetencies.js @@ -21,22 +21,22 @@ angular.module('mm.addons.competency') * @ngdoc controller * @name mmaCourseCompetenciesCtrl */ -.controller('mmaCourseCompetenciesCtrl', function($scope, $log, $stateParams, $mmaCompetency, $mmUtil, $state, $ionicPlatform, $q) { - - $log = $log.getInstance('mmaCourseCompetenciesCtrl'); +.controller('mmaCourseCompetenciesCtrl', function($scope, $stateParams, $mmaCompetency, $mmUtil, $state, $ionicPlatform, $q, + $mmaCompetencyHelper) { var courseId = parseInt($stateParams.courseid); + userId = parseInt($stateParams.userid) || false; // Convenience function that fetches the event and updates the scope. - function fetchCourseCompetencies(refresh) { + function fetchCourseCompetencies() { return $mmaCompetency.getCourseCompetencies(courseId).then(function(competencies) { $scope.competencies = competencies; - }, function(message) { - if (!refresh) { - // Some call failed, retry without using cache. - return refreshAllData(); - } + // Get the user profile image. + $mmaCompetencyHelper.getProfile(userId).then(function(user) { + $scope.user = user; + }); + }, function(message) { if (message) { $mmUtil.showErrorModal(message); } else { @@ -49,29 +49,26 @@ angular.module('mm.addons.competency') $scope.gotoCompetency = function(competencyId) { if ($ionicPlatform.isTablet()) { // Show split view on tablet. - $state.go('site.competencies', {cid: courseId, compid: competencyId}); + $state.go('site.competencies', {cid: courseId, compid: competencyId, uid: userId}); } else { - $state.go('site.competency', {courseid: courseId, competencyid: competencyId}); + $state.go('site.competency', {courseid: courseId, competencyid: competencyId, userid: userId}); } }; // Convenience function to refresh all the data. function refreshAllData() { return $mmaCompetency.invalidateCourseCompetencies(courseId).finally(function() { - return fetchCourseCompetencies(true); + return fetchCourseCompetencies(); }); } - // Get event. fetchCourseCompetencies().finally(function() { - //$mmaCompetency.logPlanView(courseId); - }).finally(function() { $scope.competenciesLoaded = true; }); // Pull to refresh. $scope.refreshCourseCompetencies = function() { - fetchCourseCompetencies(true).finally(function() { + refreshAllData().finally(function() { $scope.$broadcast('scroll.refreshComplete'); }); }; diff --git a/www/addons/competency/controllers/plan.js b/www/addons/competency/controllers/plan.js index 9a4801d880b..817f0b3e8fb 100644 --- a/www/addons/competency/controllers/plan.js +++ b/www/addons/competency/controllers/plan.js @@ -21,31 +21,27 @@ angular.module('mm.addons.competency') * @ngdoc controller * @name mmaLearningPlanCtrl */ -.controller('mmaLearningPlanCtrl', function($scope, $log, $stateParams, $mmaCompetency, $mmUtil, $translate, +.controller('mmaLearningPlanCtrl', function($scope, $stateParams, $mmaCompetency, $mmUtil, $translate, mmaCompetencyStatusDraft, mmaCompetencyStatusActive, mmaCompetencyStatusComplete, mmaCompetencyStatusWaitingForReview, - mmaCompetencyStatusInReview, $state, $ionicPlatform, $q) { - - $log = $log.getInstance('mmaLearningPlanCtrl'); + mmaCompetencyStatusInReview, $state, $ionicPlatform, $q, $mmaCompetencyHelper) { var planId = parseInt($stateParams.id); // Convenience function that fetches the event and updates the scope. - function fetchLearningPlan(refresh) { + function fetchLearningPlan() { return $mmaCompetency.getLearningPlan(planId).then(function(plan) { - var statusName; + var statusName, userId; - statusName = getStatusName(plan.plan.status); - if (statusName) { - plan.plan.statusname = statusName; - } + plan.plan.statusname = getStatusName(plan.plan.status); + + userId = plan.plan.userid; + // Get the user profile image. + $mmaCompetencyHelper.getProfile(userId).then(function(user) { + $scope.user = user; + }); $scope.plan = plan; }, function(message) { - if (!refresh) { - // Some call failed, retry without using cache. - return refreshAllData(); - } - if (message) { $mmUtil.showErrorModal(message); } else { @@ -85,7 +81,7 @@ angular.module('mm.addons.competency') break; default: // We can use the current status name. - return false; + return status; } return $translate.instant('mma.competency.planstatus' + statusTranslateName); } @@ -93,20 +89,17 @@ angular.module('mm.addons.competency') // Convenience function to refresh all the data. function refreshAllData() { return $mmaCompetency.invalidateLearningPlan(planId).finally(function() { - return fetchLearningPlan(true); + return fetchLearningPlan(); }); } - // Get event. fetchLearningPlan().finally(function() { - //$mmaCompetency.logPlanView(planId); - }).finally(function() { $scope.planLoaded = true; }); // Pull to refresh. $scope.refreshLearningPlan = function() { - fetchLearningPlan(true).finally(function() { + refreshAllData().finally(function() { $scope.$broadcast('scroll.refreshComplete'); }); }; diff --git a/www/addons/competency/controllers/list.js b/www/addons/competency/controllers/planlist.js similarity index 68% rename from www/addons/competency/controllers/list.js rename to www/addons/competency/controllers/planlist.js index 2079d109c39..57ef9456634 100644 --- a/www/addons/competency/controllers/list.js +++ b/www/addons/competency/controllers/planlist.js @@ -21,20 +21,15 @@ angular.module('mm.addons.competency') * @ngdoc controller * @name mmaLearningPlansListCtrl */ -.controller('mmaLearningPlansListCtrl', function($scope, $log, $mmaCompetency, $mmUtil, $q) { +.controller('mmaLearningPlansListCtrl', function($scope, $mmaCompetency, $mmUtil, $q, $stateParams, $mmaCompetencyHelper) { - $log = $log.getInstance('mmaLearningPlansListCtrl'); + var userId = parseInt($stateParams.userid) || false; - function fetchLearningPlans(refresh) { + function fetchLearningPlans() { - return $mmaCompetency.getLearningPlans().then(function(plans) { + return $mmaCompetency.getLearningPlans(userId).then(function(plans) { $scope.plans = plans; }).catch(function(message) { - if (!refresh) { - // Some call failed, retry without using cache. - return refreshAllData(); - } - if (message) { $mmUtil.showErrorModal(message); } else { @@ -46,14 +41,12 @@ angular.module('mm.addons.competency') // Convenience function to refresh all the data. function refreshAllData() { - return $mmaCompetency.invalidateLearningPlans().finally(function() { - return fetchLearningPlans(true); + return $mmaCompetency.invalidateLearningPlans(userId).finally(function() { + return fetchLearningPlans(); }); } - fetchLearningPlans().then(function() { - //$mmaCompetency.logPageView(currentPage); - }).finally(function() { + fetchLearningPlans().finally(function() { $scope.plansLoaded = true; }); diff --git a/www/addons/competency/lang/en.json b/www/addons/competency/lang/en.json index c04c9f6b495..bc9cc38a4cf 100644 --- a/www/addons/competency/lang/en.json +++ b/www/addons/competency/lang/en.json @@ -1,6 +1,7 @@ { "activities": "Activities", "competencies": "Competencies", + "competenciesmostoftennotproficientincourse": "Competencies most often not proficient in this course", "coursecompetencyratingsarenotpushedtouserplans": "Competency ratings in this course do not affect learning plans.", "coursecompetencyratingsarepushedtouserplans": "Competency ratings in this course are updated immediately in learning plans.", "coursecompetencies": "Course competencies", @@ -18,6 +19,7 @@ "evidence_manualoverrideincourse": "The competency rating was manually set in the course {{a}}.", "evidence_manualoverrideinplan": "The competency rating was manually set in the learning plan {{a}}.", "learningplancompetencies": "Learning plan competencies", + "learningplans": "Learning plans", "noactivities": "No activities", "mylearningplans": "My learning plans", "nocrossreferencedcompetencies": "No other competencies have been cross-referenced to this competency.", diff --git a/www/addons/competency/main.js b/www/addons/competency/main.js index 63244da4a28..6e8ea3d32ba 100644 --- a/www/addons/competency/main.js +++ b/www/addons/competency/main.js @@ -25,16 +25,19 @@ angular.module('mm.addons.competency', []) .constant('mmaCompetencyReviewStatusWaitingForReview', 1) .constant('mmaCompetencyReviewStatusInReview', 2) -.config(function($stateProvider, $mmSideMenuDelegateProvider, $mmCoursesDelegateProvider, mmaCompetencyPriority, - mmaCourseCompetenciesPriority) { +.config(function($stateProvider, $mmSideMenuDelegateProvider, $mmCoursesDelegateProvider, $mmUserDelegateProvider, + mmaCompetencyPriority, mmaCourseCompetenciesPriority) { $stateProvider .state('site.learningplans', { url: '/learningplans', + params: { + userid: null + }, views: { 'site': { controller: 'mmaLearningPlansListCtrl', - templateUrl: 'addons/competency/templates/list.html' + templateUrl: 'addons/competency/templates/planlist.html' } } }) @@ -55,9 +58,10 @@ angular.module('mm.addons.competency', []) .state('site.competencies', { url: '/competencies', params: { - pid: null, - cid: null, - compid: null + pid: null, // Not naming it planid because it collides with 'site.competency' param in split-view. + cid: null, // Not naming it courseid because it collides with 'site.competency' param in split-view. + compid: null, // Not naming it competencyid because it collides with 'site.competency' param in split-view. + uid: null // Not naming it userid because it collides with 'site.competency' param in split-view. }, views: { 'site': { @@ -72,7 +76,8 @@ angular.module('mm.addons.competency', []) params: { planid: null, courseid: null, - competencyid: null + competencyid: null, + userid: null }, views: { 'site': { @@ -85,7 +90,8 @@ angular.module('mm.addons.competency', []) .state('site.coursecompetencies', { url: '/coursecompetencies', params: { - courseid: null + courseid: null, + userid: null }, views: { 'site': { @@ -115,4 +121,8 @@ angular.module('mm.addons.competency', []) // Register courses handler. $mmCoursesDelegateProvider.registerNavHandler('mmaCompetency', '$mmaCompetencyHandlers.coursesNav', mmaCourseCompetenciesPriority); + + // Register user profile addons. + $mmUserDelegateProvider.registerProfileHandler('mmaCompetency:learningPlan', '$mmaCompetencyHandlers.learningPlan', + mmaCompetencyPriority); }); \ No newline at end of file diff --git a/www/addons/competency/services/competency.js b/www/addons/competency/services/competency.js index e433cc5b23c..23e4da9902b 100644 --- a/www/addons/competency/services/competency.js +++ b/www/addons/competency/services/competency.js @@ -21,7 +21,7 @@ angular.module('mm.addons.competency') * @ngdoc service * @name $mmaCompetency */ -.factory('$mmaCompetency', function($log, $mmSite, $mmSitesManager, $q) { +.factory('$mmaCompetency', function($log, $mmSite, $mmSitesManager, $q, mmaCompetencyStatusComplete) { $log = $log.getInstance('$mmaCompetency'); @@ -98,15 +98,16 @@ angular.module('mm.addons.competency') * @ngdoc method * @name $mmaCompetency#isPluginEnabled * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Boolean} True if competency learning plans WS is available, false otherwise. + * @return {Promise} True if competency learning plans WS is available, false otherwise. */ self.isPluginEnabled = function(siteId) { siteId = siteId || $mmSite.getId(); return $mmSitesManager.getSite(siteId).then(function(site) { - return site.wsAvailable('core_competency_list_course_competencies') && - site.wsAvailable('tool_lp_data_for_plans_page') && - self.getLearningPlans(false, siteId); + if (site.wsAvailable('core_competency_list_course_competencies') && site.wsAvailable('tool_lp_data_for_plans_page')) { + return self.getLearningPlans(false, siteId); + } + return false; }); }; @@ -118,22 +119,24 @@ angular.module('mm.addons.competency') * @name $mmaCompetency#isPluginForCourseEnabled * @param {Number} courseId Course ID. * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Boolean} + * @return {Promise} competencies if enabled for the given course, false otherwise. */ self.isPluginForCourseEnabled = function(courseId, siteId) { - siteId = siteId || $mmSite.getId(); + if (!$mmSite.isLoggedIn()) { + return $q.when(false); + } - return $mmSitesManager.getSite(siteId).then(function(site) { - if (!site.isLoggedIn()) { - return false; - } - if(!self.isPluginEnabled(siteId)) { - return false; - } - if (!self.getCourseCompetencies(courseId, siteId)) { + if (!self.isPluginEnabled(siteId)) { + return $q.when(false); + } + + return self.getCourseCompetencies(courseId, siteId).then(function(competencies) { + if (competencies.competencies.length <= 0) { return false; } - return true; + return competencies; + }).catch(function() { + return $q.when(false); }); }; @@ -314,14 +317,14 @@ angular.module('mm.addons.competency') }; /** - * Get a certain competency summary. + * Get an specific competency summary. * * @module mm.addons.competency * @ngdoc method * @name $mmaCompetency#getCourseCompetencies - * @param {Number} [courseId] ID of the course. + * @param {Number} courseId ID of the course. * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Promise} Promise to be resolved when the plans are retrieved. + * @return {Promise} Promise to be resolved when the course competencies are retrieved. */ self.getCourseCompetencies = function(courseId, siteId) { siteId = siteId || $mmSite.getId(); @@ -353,7 +356,7 @@ angular.module('mm.addons.competency') * @name $mmaCompetency#invalidateLearningPlans * @param {Number} [userId] ID of the user. If not defined, current user. * @param {String} [siteId] Site ID. If not defined, current site. - * @return {Promise} Promise resolved when the data is invalidated. + * @return {Promise} Promise resolved when the data is invalidated. */ self.invalidateLearningPlans = function(userId, siteId) { siteId = siteId || $mmSite.getId(); @@ -462,23 +465,29 @@ angular.module('mm.addons.competency') * @ngdoc method * @name $mmaCompetency#logCompetencyInPlanView * @param {Number} planId ID of the plan. - * @param {Number} competencyId ID of the competency. + * @param {Number} competencyId ID of the competency. + * @param {Number} planStatus Current plan Status to decide what action should be logged. * @param {String} [userId] User ID. If not defined, current user. * @param {String} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved when the WS call is successful. */ - self.logCompetencyInPlanView = function(planId, competencyId, userId, siteId) { + self.logCompetencyInPlanView = function(planId, competencyId, planStatus, userId, siteId) { if (planId && competencyId) { siteId = siteId || $mmSite.getId(); - userId = userId || $mmSite.getUserId(); return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + var params = { planid: planId, competencyid: competencyId, userid: userId }; - return site.write('core_competency_user_competency_viewed_in_plan', params); + if (planStatus == mmaCompetencyStatusComplete) { + return site.write('core_competency_user_competency_plan_viewed', params); + } else { + return site.write('core_competency_user_competency_viewed_in_plan', params); + } }); } return $q.reject(); @@ -499,9 +508,10 @@ angular.module('mm.addons.competency') self.logCompetencyInCourseView = function(courseId, competencyId, userId, siteId) { if (courseId && competencyId) { siteId = siteId || $mmSite.getId(); - userId = userId || $mmSite.getUserId(); return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + var params = { courseid: courseId, competencyid: competencyId, diff --git a/www/addons/competency/services/handlers.js b/www/addons/competency/services/handlers.js index 7c874584da0..40ffb30e6d7 100644 --- a/www/addons/competency/services/handlers.js +++ b/www/addons/competency/services/handlers.js @@ -27,7 +27,9 @@ angular.module('mm.addons.competency') $log = $log.getInstance('$mmaCompetencyHandlers'); var self = {}, - coursesNavEnabledCache = {}; + coursesNavEnabledCache = {}, + participantsNavEnabledCache = {}, + usersNavEnabledCache = {}; /** * Clear courses nav cache. @@ -40,6 +42,18 @@ angular.module('mm.addons.competency') coursesNavEnabledCache = {}; }; + /** + * Clear users nav cache. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetencyHandlers#clearUsersNavCache + */ + self.clearUsersNavCache = function() { + participantsNavEnabledCache = {}; + usersNavEnabledCache = {}; + }; + /** * Side menu nav handler. * @@ -126,10 +140,14 @@ angular.module('mm.addons.competency') if (accessData && accessData.type == mmCoursesAccessMethods.guest) { return false; // Not enabled for guests. } + if (typeof coursesNavEnabledCache[courseId] != 'undefined') { return coursesNavEnabledCache[courseId]; } - return $mmaCompetency.isPluginForCourseEnabled(courseId).then(function(enabled) { + return $mmaCompetency.isPluginForCourseEnabled(courseId).then(function(competencies) { + var enabled = competencies ? !competencies.canmanagecoursecompetencies : false; + // We can also cache call for participantsNav. + participantsNavEnabledCache[courseId] = !!competencies; coursesNavEnabledCache[courseId] = enabled; return enabled; }); @@ -167,12 +185,117 @@ angular.module('mm.addons.competency') return self; }; + /** + * Learning Plan User handler. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetencyHandlers#learningPlan + */ + self.learningPlan = function() { + + var self = {}; + + /** + * Check if handler is enabled. + * + * @return {Boolean} True if handler is enabled, false otherwise. + */ + self.isEnabled = function() { + return $mmaCompetency.isPluginEnabled(); + }; + + /** + * Check if handler is enabled for this course. + * + * @param {Number} user User to check. + * @param {Number} courseId Course ID. + * @return {Boolean} True if handler is enabled, false otherwise. + */ + self.isEnabledForUser = function(user, courseId) { + + if (courseId) { + // Link on a user course profile. + if (typeof participantsNavEnabledCache[courseId] != 'undefined') { + return participantsNavEnabledCache[courseId]; + } + return $mmaCompetency.isPluginForCourseEnabled(courseId).then(function(competencies) { + var enabled = !!competencies; + // We can also cache call for coursesNav. + coursesNavEnabledCache[courseId] = competencies ? !competencies.canmanagecoursecompetencies : false; + participantsNavEnabledCache[courseId] = enabled; + return enabled; + }); + } else { + // Link on a user site profile. + if (typeof usersNavEnabledCache[user.id] != 'undefined') { + return usersNavEnabledCache[user.id]; + } + return $mmaCompetency.getLearningPlans(user.id).then(function(plans) { + // Check the user has at least one learn plan available. + var enabled = plans.length > 0; + usersNavEnabledCache[user.id] = enabled; + return enabled; + }); + } + }; + + /** + * Get the controller. + * + * @param {Object} user User. + * @param {Number} courseId Course ID. + * @return {Object} Controller. + */ + self.getController = function(user, courseId) { + + + /** + * Learning plan handler controller. + * + * @module mm.addons.competency + * @ngdoc controller + * @name $mmaCompetencyHandlers#learningPlan:controller + */ + return function($scope, $state) { + $scope.class = 'mma-competency-handler'; + if (courseId) { + $scope.icon = 'ion-ribbon-a'; + $scope.title = 'mma.competency.competencies'; + $scope.action = function($event) { + $event.preventDefault(); + $event.stopPropagation(); + $state.go('site.coursecompetencies', { + courseid: courseId, + userid: user.id + }); + }; + } else { + $scope.icon = 'ion-map'; + $scope.title = 'mma.competency.learningplans'; + $scope.action = function($event) { + $event.preventDefault(); + $event.stopPropagation(); + $state.go('site.learningplans', { + userid: user.id + }); + }; + } + }; + + }; + + return self; + }; + return self; }) -.run(function($mmaCompetencyHandlers, $mmEvents, mmCoreEventLogout, mmCoursesEventMyCoursesRefreshed) { +.run(function($mmaCompetencyHandlers, $mmEvents, mmCoreEventLogout, mmCoursesEventMyCoursesRefreshed, mmUserEventProfileRefreshed) { $mmEvents.on(mmCoreEventLogout, function() { $mmaCompetencyHandlers.clearCoursesNavCache(); + $mmaCompetencyHandlers.clearUsersNavCache(); }); $mmEvents.on(mmCoursesEventMyCoursesRefreshed, $mmaCompetencyHandlers.clearCoursesNavCache); + $mmEvents.on(mmUserEventProfileRefreshed, $mmaCompetencyHandlers.clearUsersNavCache); }); diff --git a/www/addons/competency/services/helper.js b/www/addons/competency/services/helper.js new file mode 100644 index 00000000000..9da69f5d043 --- /dev/null +++ b/www/addons/competency/services/helper.js @@ -0,0 +1,45 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +angular.module('mm.addons.competency') + +.factory('$mmaCompetencyHelper', function($mmUser, $mmSite, $log, $q) { + + $log = $log.getInstance('$mmaCompetencyHelper'); + + var self = {}; + + /** + * Convenient helper to get the user profile image. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetencyHelper#getProfile + * @param {Integer} userId User Id + * @return {Promise} User profile Image URL or true if default icon. + */ + self.getProfile = function(userId) { + if (!userId || userId == $mmSite.getUserId()) { + return $q.when(false); + } + + // Get the user profile to retrieve the user image. + return $mmUser.getProfile(userId, undefined, true).then(function(user) { + user.profileimageurl = user.profileimageurl || true; + return user; + }); + }; + + return self; +}); diff --git a/www/addons/competency/templates/competency.html b/www/addons/competency/templates/competency.html index d6a1f0eaa4e..206c5a5cbf6 100644 --- a/www/addons/competency/templates/competency.html +++ b/www/addons/competency/templates/competency.html @@ -6,6 +6,11 @@ on-refresh="refreshCompetency()"> +

+ {{ 'mm.core.pictureof' | translate:{$a: user.fullname} }} + + {{ user.fullname }} +