diff --git a/www/addons/competency/controllers/competencies.js b/www/addons/competency/controllers/competencies.js new file mode 100644 index 00000000000..d7844588020 --- /dev/null +++ b/www/addons/competency/controllers/competencies.js @@ -0,0 +1,119 @@ +// (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, $mmaCompetency, $mmUtil, $stateParams, $state, $ionicPlatform, $q, + $translate, $mmaCompetencyHelper) { + + var planId = parseInt($stateParams.pid) || false, + courseId = parseInt($stateParams.cid) || false, + competencyId = parseInt($stateParams.compid), + userId = parseInt($stateParams.uid) || false; + + function fetchCompetencies() { + 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'; + userId = response.plan.userid; + } else { + $scope.title = $translate.instant('mma.competency.coursecompetencies'); + $scope.id = response.courseid; + $scope.idname = 'courseid'; + } + + $scope.competencies = response.competencies; + }).catch(function(message) { + 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, userid: userId}); + } + }; + + // 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(); + }); + } + + // 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..2c50d41fd87 --- /dev/null +++ b/www/addons/competency/controllers/competency.js @@ -0,0 +1,132 @@ +// (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 mmaCompetencyCtrl + */ +.controller('mmaCompetencyCtrl', function($scope, $stateParams, $mmaCompetency, $mmUtil, $translate, $q, $mmSite, + mmaCompetencyReviewStatusIdle, mmaCompetencyReviewStatusInReview, mmaCompetencyReviewStatusWaitingForReview) { + + var competencyId = parseInt($stateParams.competencyid), + planId = parseInt($stateParams.planid) || 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() { + + if (planId) { + planStatus = false; + promise = $mmaCompetency.getCompetencyInPlan(planId, competencyId); + } else if (courseId){ + promise = $mmaCompetency.getCompetencyInCourse(courseId, competencyId, userId); + } else { + promise = $q.reject(); + } + + return promise.then(function(competency) { + + if (planId) { + 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}); + } + }); + + $scope.competency = competency.usercompetencysummary; + + }, function(message) { + 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 status; + } + 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(); + }); + } + + fetchCompetency().then(function() { + if (planId) { + $mmaCompetency.logCompetencyInPlanView(planId, competencyId, planStatus, userId); + } else { + $mmaCompetency.logCompetencyInCourseView(courseId, competencyId, userId); + } + }).finally(function() { + $scope.competencyLoaded = true; + }); + + // Pull to refresh. + $scope.refreshCompetency = function() { + refreshAllData().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..606f267831d --- /dev/null +++ b/www/addons/competency/controllers/competencysummary.js @@ -0,0 +1,61 @@ +// (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 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() { + return $mmaCompetency.getCompetencySummary(competencyId).then(function(competency) { + $scope.competency = competency; + }, function(message) { + 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(); + }); + } + + fetchCompetency().then(function() { + $mmaCompetency.logCompetencyView(competencyId); + }).finally(function() { + $scope.competencyLoaded = true; + }); + + // Pull to refresh. + $scope.refreshCompetency = function() { + refreshAllData().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..70ea2b502c2 --- /dev/null +++ b/www/addons/competency/controllers/coursecompetencies.js @@ -0,0 +1,75 @@ +// (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, $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() { + return $mmaCompetency.getCourseCompetencies(courseId).then(function(competencies) { + $scope.competencies = competencies; + + // Get the user profile image. + $mmaCompetencyHelper.getProfile(userId).then(function(user) { + $scope.user = user; + }); + }, function(message) { + 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, uid: userId}); + } else { + $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(); + }); + } + + fetchCourseCompetencies().finally(function() { + $scope.competenciesLoaded = true; + }); + + // Pull to refresh. + $scope.refreshCourseCompetencies = 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..817f0b3e8fb --- /dev/null +++ b/www/addons/competency/controllers/plan.js @@ -0,0 +1,106 @@ +// (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, $stateParams, $mmaCompetency, $mmUtil, $translate, + mmaCompetencyStatusDraft, mmaCompetencyStatusActive, mmaCompetencyStatusComplete, mmaCompetencyStatusWaitingForReview, + mmaCompetencyStatusInReview, $state, $ionicPlatform, $q, $mmaCompetencyHelper) { + + var planId = parseInt($stateParams.id); + + // Convenience function that fetches the event and updates the scope. + function fetchLearningPlan() { + return $mmaCompetency.getLearningPlan(planId).then(function(plan) { + var statusName, userId; + + 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 (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 status; + } + return $translate.instant('mma.competency.planstatus' + statusTranslateName); + } + + // Convenience function to refresh all the data. + function refreshAllData() { + return $mmaCompetency.invalidateLearningPlan(planId).finally(function() { + return fetchLearningPlan(); + }); + } + + fetchLearningPlan().finally(function() { + $scope.planLoaded = true; + }); + + // Pull to refresh. + $scope.refreshLearningPlan = function() { + refreshAllData().finally(function() { + $scope.$broadcast('scroll.refreshComplete'); + }); + }; +}); diff --git a/www/addons/competency/controllers/planlist.js b/www/addons/competency/controllers/planlist.js new file mode 100644 index 00000000000..57ef9456634 --- /dev/null +++ b/www/addons/competency/controllers/planlist.js @@ -0,0 +1,59 @@ +// (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, $mmaCompetency, $mmUtil, $q, $stateParams, $mmaCompetencyHelper) { + + var userId = parseInt($stateParams.userid) || false; + + function fetchLearningPlans() { + + return $mmaCompetency.getLearningPlans(userId).then(function(plans) { + $scope.plans = plans; + }).catch(function(message) { + 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(userId).finally(function() { + return fetchLearningPlans(); + }); + } + + fetchLearningPlans().finally(function() { + $scope.plansLoaded = true; + }); + + // Pull to refresh. + $scope.refreshLearningPlans = function() { + refreshAllData().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..bc9cc38a4cf --- /dev/null +++ b/www/addons/competency/lang/en.json @@ -0,0 +1,47 @@ +{ + "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", + "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", + "learningplans": "Learning plans", + "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..6e8ea3d32ba --- /dev/null +++ b/www/addons/competency/main.js @@ -0,0 +1,128 @@ +// (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, $mmUserDelegateProvider, + mmaCompetencyPriority, mmaCourseCompetenciesPriority) { + + $stateProvider + .state('site.learningplans', { + url: '/learningplans', + params: { + userid: null + }, + views: { + 'site': { + controller: 'mmaLearningPlansListCtrl', + templateUrl: 'addons/competency/templates/planlist.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, // 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': { + controller: 'mmaCompetenciesListCtrl', + templateUrl: 'addons/competency/templates/competencies.html' + } + } + }) + + .state('site.competency', { + url: '/competency', + params: { + planid: null, + courseid: null, + competencyid: null, + userid: null + }, + views: { + 'site': { + controller: 'mmaCompetencyCtrl', + templateUrl: 'addons/competency/templates/competency.html' + } + } + }) + + .state('site.coursecompetencies', { + url: '/coursecompetencies', + params: { + courseid: null, + userid: 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); + + // 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 new file mode 100644 index 00000000000..23e4da9902b --- /dev/null +++ b/www/addons/competency/services/competency.js @@ -0,0 +1,551 @@ +// (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, mmaCompetencyStatusComplete) { + + $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 {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) { + if (site.wsAvailable('core_competency_list_course_competencies') && site.wsAvailable('tool_lp_data_for_plans_page')) { + return self.getLearningPlans(false, siteId); + } + return false; + }); + }; + + /** + * 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 {Promise} competencies if enabled for the given course, false otherwise. + */ + self.isPluginForCourseEnabled = function(courseId, siteId) { + if (!$mmSite.isLoggedIn()) { + return $q.when(false); + } + + if (!self.isPluginEnabled(siteId)) { + return $q.when(false); + } + + return self.getCourseCompetencies(courseId, siteId).then(function(competencies) { + if (competencies.competencies.length <= 0) { + return false; + } + return competencies; + }).catch(function() { + return $q.when(false); + }); + }; + + /** + * 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 an specific 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 course competencies 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 {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, planStatus, userId, siteId) { + if (planId && competencyId) { + siteId = siteId || $mmSite.getId(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + + var params = { + planid: planId, + competencyid: competencyId, + userid: userId + }; + 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(); + }; + + /** + * 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(); + + return $mmSitesManager.getSite(siteId).then(function(site) { + userId = userId || site.getUserId(); + + 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..40ffb30e6d7 --- /dev/null +++ b/www/addons/competency/services/handlers.js @@ -0,0 +1,301 @@ +// (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 = {}, + participantsNavEnabledCache = {}, + usersNavEnabledCache = {}; + + /** + * Clear courses nav cache. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetencyHandlers#clearCoursesNavCache + */ + self.clearCoursesNavCache = function() { + coursesNavEnabledCache = {}; + }; + + /** + * Clear users nav cache. + * + * @module mm.addons.competency + * @ngdoc method + * @name $mmaCompetencyHandlers#clearUsersNavCache + */ + self.clearUsersNavCache = function() { + participantsNavEnabledCache = {}; + usersNavEnabledCache = {}; + }; + + /** + * 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(competencies) { + var enabled = competencies ? !competencies.canmanagecoursecompetencies : false; + // We can also cache call for participantsNav. + participantsNavEnabledCache[courseId] = !!competencies; + 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; + }; + + /** + * 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, 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/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..206c5a5cbf6 --- /dev/null +++ b/www/addons/competency/templates/competency.html @@ -0,0 +1,91 @@ + + {{ competency.competency.competency.shortname }} {{ competency.competency.competency.idnumber }} + + + + + +

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

+
+
    +
  • + {{ 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..123a3b10b3a --- /dev/null +++ b/www/addons/competency/templates/coursecompetencies.html @@ -0,0 +1,81 @@ + + {{ '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.competenciesmostoftennotproficientincourse' | translate }}: + +
  • +
+
+ +
+

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

+

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

+ + {{ '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/plan.html b/www/addons/competency/templates/plan.html new file mode 100644 index 00000000000..145b6a4f499 --- /dev/null +++ b/www/addons/competency/templates/plan.html @@ -0,0 +1,56 @@ + + {{plan.plan.name}} + + + + + +

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

+
+
    +
  • + {{ 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/addons/competency/templates/planlist.html b/www/addons/competency/templates/planlist.html new file mode 100644 index 00000000000..00c7905495c --- /dev/null +++ b/www/addons/competency/templates/planlist.html @@ -0,0 +1,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/www/addons/notes/services/handlers.js b/www/addons/notes/services/handlers.js index 754922f2528..ecb40a5360c 100644 --- a/www/addons/notes/services/handlers.js +++ b/www/addons/notes/services/handlers.js @@ -102,7 +102,7 @@ angular.module('mm.addons.notes') /** * Get the controller. * - * @param {Object} user Course ID. + * @param {Object} user User. * @param {Number} courseId Course ID. * @return {Object} Controller. */ diff --git a/www/core/lib/util.js b/www/core/lib/util.js index f9cf2ba3c62..0deb0ad6021 100644 --- a/www/core/lib/util.js +++ b/www/core/lib/util.js @@ -147,7 +147,7 @@ angular.module('mm.core') } if (typeof resolved === 'undefined') { - throw new Error('Unexpected argument passed passed'); + throw new Error('Unexpected argument object passed'); } return resolved; }; 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;