diff --git a/admin/tool/lp/amd/build/competencypicker.min.js b/admin/tool/lp/amd/build/competencypicker.min.js index dfc36a711cb..1a1dc316b37 100644 --- a/admin/tool/lp/amd/build/competencypicker.min.js +++ b/admin/tool/lp/amd/build/competencypicker.min.js @@ -1 +1 @@ -define(["jquery","core/notification","core/ajax","core/templates","tool_lp/dialogue","core/str","tool_lp/tree"],function(a,b,c,d,e,f,g){var h,i=function(b,c,d,e){h=this,h._eventNode=a("
"),h._frameworks=[],h._reset(),h._pageContextId=b,h._pageContextIncludes=d||"children",h._multiSelect="undefined"==typeof e||e===!0,c&&(h._frameworkId=c,h._singleFramework=!0)};return i.prototype._competencies=null,i.prototype._disallowedCompetencyIDs=null,i.prototype._eventNode=null,i.prototype._frameworks=null,i.prototype._frameworkId=null,i.prototype._pageContextId=null,i.prototype._pageContextIncludes=null,i.prototype._popup=null,i.prototype._searchText="",i.prototype._selectedCompetencies=null,i.prototype._singleFramework=!1,i.prototype._multiSelect=!0,i.prototype._afterRender=function(){var b=new g(h._find("[data-enhance=linktree]"),h._multiSelect);h._find("[data-enhance=linktree]").show(),b.on("selectionchanged",function(b,c){var d=c.selected;b.preventDefault();var e=[];a.each(d,function(b,c){var d=a(c).data("id"),f=!0;"undefined"==typeof d?f=!1:a.each(h._disallowedCompetencyIDs,function(a,b){b==d&&(f=!1)}),f&&e.push(d)}),h._selectedCompetencies=e,h._selectedCompetencies.length?h._find('[data-region="competencylinktree"] [data-action="add"]').removeAttr("disabled"):h._find('[data-region="competencylinktree"] [data-action="add"]').attr("disabled","disabled")}),h._singleFramework||h._find('[data-action="chooseframework"]').change(function(b){h._frameworkId=a(b.target).val(),h._loadCompetencies().then(h._refresh)}),h._find('[data-region="filtercompetencies"] button').click(function(b){return b.preventDefault(),a(b.target).attr("disabled","disabled"),h._searchText=h._find('[data-region="filtercompetencies"] input').val()||"",h._refresh().always(function(){a(b.target).removeAttr("disabled")})}),h._find('[data-region="competencylinktree"] [data-action="cancel"]').click(function(a){a.preventDefault(),h.close()}),h._find('[data-region="competencylinktree"] [data-action="add"]').click(function(a){a.preventDefault(),h._selectedCompetencies.length&&(h._multiSelect?h._trigger("save",{competencyIds:h._selectedCompetencies}):h._trigger("save",{competencyId:h._selectedCompetencies[0]}),h.close())});var c=h._selectedCompetencies.slice(0);a.each(c,function(a,c){var d=h._find("[data-id="+c+"]");d.length&&(b.toggleItem(d),b.updateFocus(d))})},i.prototype.close=function(){h._popup.close(),h._reset()},i.prototype.display=function(){return h._render().done(function(a){return f.get_string("competencypicker","tool_lp").done(function(b){h._popup=new e(b,a,h._afterRender.bind(h))})}).fail(b.exception)},i.prototype._fetchCompetencies=function(a,d){return c.call([{methodname:"tool_lp_search_competencies",args:{searchtext:d,competencyframeworkid:a}}])[0].done(function(a){function b(a,c){for(var d=0;d0?a.when():(d=h._singleFramework?c.call([{methodname:"tool_lp_read_competency_framework",args:{id:this._frameworkId}}])[0].then(function(a){return[a]}):c.call([{methodname:"tool_lp_list_competency_frameworks",args:{sort:"shortname",context:{contextid:h._pageContextId},includes:h._pageContextIncludes}}])[0],d.done(function(a){h._frameworks=a}).fail(b.exception))},i.prototype.on=function(a,b){h._eventNode.on(a,b)},i.prototype._preRender=function(){return h._loadFrameworks().then(function(){return!h._frameworkId&&h._frameworks.length>0&&(h._frameworkId=h._frameworks[0].id),h._frameworkId?h._loadCompetencies():(h._frameworks=[],a.when())})},i.prototype._refresh=function(){return h._render().then(function(a){h._find('[data-region="competencylinktree"]').replaceWith(a),h._afterRender()})},i.prototype._render=function(){return h._preRender().then(function(){h._singleFramework||a.each(h._frameworks,function(a,b){b.id==h._frameworkId?b.selected=!0:b.selected=!1});var b={competencies:h._competencies,framework:h._getFramework(h._frameworkId),frameworks:h._frameworks,search:h._searchText,singleFramework:h._singleFramework};return d.render("tool_lp/competency_picker",b)})},i.prototype._reset=function(){h._competencies=[],h._disallowedCompetencyIDs=[],h._popup=null,h._searchText="",h._selectedCompetencies=[]},i.prototype.setDisallowedCompetencyIDs=function(a){h._disallowedCompetencyIDs=a},i.prototype._trigger=function(a,b){h._eventNode.trigger(a,[b])},i}); \ No newline at end of file +define(["jquery","core/notification","core/ajax","core/templates","tool_lp/dialogue","core/str","tool_lp/tree"],function(a,b,c,d,e,f,g){var h=function(b,c,d,e){var f=this;f._eventNode=a("
"),f._frameworks=[],f._reset(),f._pageContextId=b,f._pageContextIncludes=d||"children",f._multiSelect="undefined"==typeof e||e===!0,c&&(f._frameworkId=c,f._singleFramework=!0)};return h.prototype._competencies=null,h.prototype._disallowedCompetencyIDs=null,h.prototype._eventNode=null,h.prototype._frameworks=null,h.prototype._frameworkId=null,h.prototype._pageContextId=null,h.prototype._pageContextIncludes=null,h.prototype._popup=null,h.prototype._searchText="",h.prototype._selectedCompetencies=null,h.prototype._singleFramework=!1,h.prototype._multiSelect=!0,h.prototype._afterRender=function(){var b=this,c=new g(b._find("[data-enhance=linktree]"),b._multiSelect);b._find("[data-enhance=linktree]").show(),c.on("selectionchanged",function(c,d){var e=d.selected;c.preventDefault();var f=[];a.each(e,function(c,d){var e=a(d).data("id"),g=!0;"undefined"==typeof e?g=!1:a.each(b._disallowedCompetencyIDs,function(a,b){b==e&&(g=!1)}),g&&f.push(e)}.bind(b)),b._selectedCompetencies=f,b._selectedCompetencies.length?b._find('[data-region="competencylinktree"] [data-action="add"]').removeAttr("disabled"):b._find('[data-region="competencylinktree"] [data-action="add"]').attr("disabled","disabled")}.bind(b)),b._singleFramework||b._find('[data-action="chooseframework"]').change(function(c){b._frameworkId=a(c.target).val(),b._loadCompetencies().then(b._refresh.bind(b))}.bind(b)),b._find('[data-region="filtercompetencies"] button').click(function(c){return c.preventDefault(),a(c.target).attr("disabled","disabled"),b._searchText=b._find('[data-region="filtercompetencies"] input').val()||"",b._refresh().always(function(){a(c.target).removeAttr("disabled")})}.bind(b)),b._find('[data-region="competencylinktree"] [data-action="cancel"]').click(function(a){a.preventDefault(),b.close()}.bind(b)),b._find('[data-region="competencylinktree"] [data-action="add"]').click(function(a){a.preventDefault(),b._selectedCompetencies.length&&(b._multiSelect?b._trigger("save",{competencyIds:b._selectedCompetencies}):b._trigger("save",{competencyId:b._selectedCompetencies[0]}),b.close())}.bind(b));var d=b._selectedCompetencies.slice(0);a.each(d,function(a,d){var e=b._find("[data-id="+d+"]");e.length&&(c.toggleItem(e),c.updateFocus(e))}.bind(b))},h.prototype.close=function(){var a=this;a._popup.close(),a._reset()},h.prototype.display=function(){var a=this;return a._render().then(function(b){return f.get_string("competencypicker","tool_lp").then(function(c){a._popup=new e(c,b,a._afterRender.bind(a))}.bind(a))}.bind(a)).fail(b.exception)},h.prototype._fetchCompetencies=function(a,d){var e=this;return c.call([{methodname:"tool_lp_search_competencies",args:{searchtext:d,competencyframeworkid:a}}])[0].done(function(a){function b(a,c){for(var d=0;d0?a.when():(d=e._singleFramework?c.call([{methodname:"tool_lp_read_competency_framework",args:{id:this._frameworkId}}])[0].then(function(a){return[a]}):c.call([{methodname:"tool_lp_list_competency_frameworks",args:{sort:"shortname",context:{contextid:e._pageContextId},includes:e._pageContextIncludes}}])[0],d.done(function(a){e._frameworks=a}).fail(b.exception))},h.prototype.on=function(a,b){this._eventNode.on(a,b)},h.prototype._preRender=function(){var b=this;return b._loadFrameworks().then(function(){return!b._frameworkId&&b._frameworks.length>0&&(b._frameworkId=b._frameworks[0].id),b._frameworkId?b._loadCompetencies():(b._frameworks=[],a.when())}.bind(b))},h.prototype._refresh=function(){var a=this;return a._render().then(function(b){a._find('[data-region="competencylinktree"]').replaceWith(b),a._afterRender()}.bind(a))},h.prototype._render=function(){var b=this;return b._preRender().then(function(){b._singleFramework||a.each(b._frameworks,function(a,c){c.id==b._frameworkId?c.selected=!0:c.selected=!1});var c={competencies:b._competencies,framework:b._getFramework(b._frameworkId),frameworks:b._frameworks,search:b._searchText,singleFramework:b._singleFramework};return d.render("tool_lp/competency_picker",c)}.bind(b))},h.prototype._reset=function(){this._competencies=[],this._disallowedCompetencyIDs=[],this._popup=null,this._searchText="",this._selectedCompetencies=[]},h.prototype.setDisallowedCompetencyIDs=function(a){this._disallowedCompetencyIDs=a},h.prototype._trigger=function(a,b){this._eventNode.trigger(a,[b])},h}); \ No newline at end of file diff --git a/admin/tool/lp/amd/build/competencypicker_user_plans.min.js b/admin/tool/lp/amd/build/competencypicker_user_plans.min.js new file mode 100644 index 00000000000..1191fad69c2 --- /dev/null +++ b/admin/tool/lp/amd/build/competencypicker_user_plans.min.js @@ -0,0 +1 @@ +define(["jquery","core/notification","core/ajax","core/templates","core/str","tool_lp/tree","tool_lp/competencypicker"],function(a,b,c,d,e,f,g){var h=function(a,b,c){g.prototype.constructor.apply(this,[1,!1,"self",c]),this._userId=a,this._plans=[],b&&(this._planId=b,this._singlePlan=!0)};return h.prototype=Object.create(g.prototype),h.prototype._plans=null,h.prototype._planId=null,h.prototype._singlePlan=!1,h.prototype._userId=null,h.prototype._afterRender=function(){var b=this;g.prototype._afterRender.apply(b,arguments),b._singlePlan||b._find('[data-action="chooseplan"]').change(function(c){b._planId=a(c.target).val(),b._loadCompetencies().then(b._refresh.bind(b))}.bind(b))},h.prototype._fetchCompetencies=function(a,d){var e=this;return c.call([{methodname:"tool_lp_list_plan_competencies",args:{id:a}}])[0].done(function(a){var b,c,f=[];for(b=0;b0?a.when():(d=e._singlePlan?c.call([{methodname:"tool_lp_read_plan",args:{id:this._planId}}])[0].then(function(a){return[a]}):c.call([{methodname:"tool_lp_list_user_plans",args:{userid:e._userId}}])[0],d.done(function(a){e._plans=a}).fail(b.exception))},h.prototype._preRender=function(){var b=this;return b._loadPlans().then(function(){return!b._planId&&b._plans.length>0&&(b._planId=b._plans[0].id),b._planId?b._loadCompetencies():(b._plans=[],a.when())}.bind(b))},h.prototype._render=function(){var b=this;return b._preRender().then(function(){b._singlePlan||a.each(b._plans,function(a,c){c.id==b._planId?c.selected=!0:c.selected=!1});var c={competencies:b._competencies,plan:b._getPlan(b._planId),plans:b._plans,search:b._searchText,singlePlan:b._singlePlan};return d.render("tool_lp/competency_picker_user_plans",c)}.bind(b))},h}); \ No newline at end of file diff --git a/admin/tool/lp/amd/build/user_evidence_actions.min.js b/admin/tool/lp/amd/build/user_evidence_actions.min.js new file mode 100644 index 00000000000..3500cfdd5b6 --- /dev/null +++ b/admin/tool/lp/amd/build/user_evidence_actions.min.js @@ -0,0 +1 @@ +define(["jquery","core/templates","core/ajax","core/notification","core/str","tool_lp/menubar","tool_lp/competencypicker_user_plans"],function(a,b,c,d,e,f,g){var h=function(a){if(this._type=a,"evidence"===a)this._region='[data-region="user-evidence-page"]',this._evidenceNode='[data-region="user-evidence-page"]',this._template="tool_lp/user_evidence_page",this._contextMethod="tool_lp_data_for_user_evidence_page";else{if("list"!==a)throw new TypeError("Unexpected type.");this._region='[data-region="user-evidence-list"]',this._evidenceNode='[data-region="user-evidence-node"]',this._template="tool_lp/user_evidence_list_page",this._contextMethod="tool_lp_data_for_user_evidence_list_page"}};return h.prototype._contextMethod=null,h.prototype._evidenceNode=null,h.prototype._region=null,h.prototype._template=null,h.prototype._type=null,h.prototype._getContextArgs=function(a){var b=this,c={};return"evidence"===b._type?c={id:a.id}:"list"===b._type&&(c={userid:a.userid}),c},h.prototype._renderView=function(c){var e=this;b.render(e._template,c).done(function(c,d){b.replaceNode(a(e._region),c,d)}.bind(e)).fail(d.exception)},h.prototype._callAndRefresh=function(b,e){var f=this;return b.push({methodname:f._contextMethod,args:f._getContextArgs(e)}),a.when.apply(a.when,c.call(b)).then(function(){f._renderView.call(f,arguments[arguments.length-1])}).fail(d.exception)},h.prototype._doDelete=function(a){var b=this,c=[{methodname:"tool_lp_delete_user_evidence",args:{id:a.id}}];b._callAndRefresh(c,a)},h.prototype.deleteEvidence=function(a){var b,f=this;b=c.call([{methodname:"tool_lp_read_user_evidence",args:{id:a.id}}]),b[0].done(function(b){e.get_strings([{key:"confirm",component:"moodle"},{key:"deleteuserevidence",component:"tool_lp",param:b.name},{key:"delete",component:"moodle"},{key:"cancel",component:"moodle"}]).done(function(b){d.confirm(b[0],b[1],b[2],b[3],function(){f._doDelete(a)}.bind(f))}).fail(d.exception)}).fail(d.exception)},h.prototype._deleteEvidenceHandler=function(b){b.preventDefault();var c=this._findEvidenceData(a(b.target));this.deleteEvidence(c)},h.prototype._doCreateUserEvidenceCompetency=function(b,c){var d=this,e=[];a.each(c,function(a,c){e.push({methodname:"tool_lp_create_user_evidence_competency",args:{userevidenceid:b.id,competencyid:c}})}),d._callAndRefresh(e,b)},h.prototype.createUserEvidenceCompetency=function(a){var b=this,c=new g(a.userid);c.on("save",function(c,d){var e=d.competencyIds;b._doCreateUserEvidenceCompetency(a,e)}.bind(b)),c.display()},h.prototype._createUserEvidenceCompetencyHandler=function(b){b.preventDefault();var c=this._findEvidenceData(a(b.target));this.createUserEvidenceCompetency(c)},h.prototype._doDeleteUserEvidenceCompetency=function(a,b){var c=this,d=[];d.push({methodname:"tool_lp_delete_user_evidence_competency",args:{userevidenceid:a.id,competencyid:b}}),c._callAndRefresh(d,a)},h.prototype.deleteUserEvidenceCompetency=function(a,b){this._doDeleteUserEvidenceCompetency(a,b)},h.prototype._deleteUserEvidenceCompetencyHandler=function(b){var c=this._findEvidenceData(a(b.currentTarget)),d=a(b.currentTarget).data("id");b.preventDefault(),this.deleteUserEvidenceCompetency(c,d)},h.prototype._findEvidenceData=function(b){var c,d=b.parentsUntil(a(this._region).parent(),this._evidenceNode);if(1!=d.length)throw new Error("The evidence node was not located.");if(c=d.data(),"undefined"==typeof c||"undefined"==typeof c.id)throw new Error("Evidence data could not be found.");return c},h.prototype.enhanceMenubar=function(a){var b=this;f.enhance(a,{'[data-action="user-evidence-delete"]':b._deleteEvidenceHandler.bind(b),'[data-action="link-competency"]':b._createUserEvidenceCompetencyHandler.bind(b)})},h.prototype.registerEvents=function(){var b=a(this._region),c=this;b.find('[data-action="user-evidence-delete"]').click(c._deleteEvidenceHandler.bind(c)),b.find('[data-action="link-competency"]').click(c._createUserEvidenceCompetencyHandler.bind(c)),b.find('[data-action="delete-competency-link"]').click(c._deleteUserEvidenceCompetencyHandler.bind(c))},h}); \ No newline at end of file diff --git a/admin/tool/lp/amd/src/competencypicker.js b/admin/tool/lp/amd/src/competencypicker.js index 55b0ea29c95..1d917a6604a 100644 --- a/admin/tool/lp/amd/src/competencypicker.js +++ b/admin/tool/lp/amd/src/competencypicker.js @@ -34,8 +34,6 @@ define(['jquery', 'tool_lp/tree'], function($, Notification, Ajax, Templates, Dialogue, Str, Tree) { - var self; - /** * Competency picker class. * @param {Number} pageContextId The page context ID. @@ -44,7 +42,7 @@ define(['jquery', * @param {Boolean} multiSelect Support multi-select in the tree. */ var Picker = function(pageContextId, singleFramework, pageContextIncludes, multiSelect) { - self = this; + var self = this; self._eventNode = $('
'); self._frameworks = []; self._reset(); @@ -89,6 +87,7 @@ define(['jquery', * @method _afterRender */ Picker.prototype._afterRender = function() { + var self = this; // Initialise the tree. var tree = new Tree(self._find('[data-enhance=linktree]'), self._multiSelect); @@ -117,7 +116,7 @@ define(['jquery', if (valid) { validIds.push(compId); } - }); + }.bind(self)); self._selectedCompetencies = validIds; @@ -127,14 +126,14 @@ define(['jquery', } else { self._find('[data-region="competencylinktree"] [data-action="add"]').removeAttr('disabled'); } - }); + }.bind(self)); // Add listener for framework change. if (!self._singleFramework) { self._find('[data-action="chooseframework"]').change(function(e) { self._frameworkId = $(e.target).val(); - self._loadCompetencies().then(self._refresh); - }); + self._loadCompetencies().then(self._refresh.bind(self)); + }.bind(self)); } // Add listener for search. @@ -145,13 +144,13 @@ define(['jquery', return self._refresh().always(function() { $(e.target).removeAttr('disabled'); }); - }); + }.bind(self)); // Add listener for cancel. self._find('[data-region="competencylinktree"] [data-action="cancel"]').click(function(e) { e.preventDefault(); self.close(); - }); + }.bind(self)); // Add listener for add. self._find('[data-region="competencylinktree"] [data-action="add"]').click(function(e) { @@ -168,7 +167,7 @@ define(['jquery', } self.close(); - }); + }.bind(self)); // The list of selected competencies will be modified while looping (because of the listeners above). var currentItems = self._selectedCompetencies.slice(0); @@ -179,7 +178,7 @@ define(['jquery', tree.toggleItem(node); tree.updateFocus(node); } - }); + }.bind(self)); }; @@ -189,6 +188,7 @@ define(['jquery', * @method close */ Picker.prototype.close = function() { + var self = this; self._popup.close(); self._reset(); }; @@ -200,15 +200,16 @@ define(['jquery', * @return {Promise} */ Picker.prototype.display = function() { - return self._render().done(function(html) { - return Str.get_string('competencypicker', 'tool_lp').done(function(title) { + var self = this; + return self._render().then(function(html) { + return Str.get_string('competencypicker', 'tool_lp').then(function(title) { self._popup = new Dialogue( title, html, self._afterRender.bind(self) ); - }); - }).fail(Notification.exception); + }.bind(self)); + }.bind(self)).fail(Notification.exception); }; /** @@ -220,6 +221,8 @@ define(['jquery', * @return {Promise} */ Picker.prototype._fetchCompetencies = function(frameworkId, searchText) { + var self = this; + return Ajax.call([ { methodname: 'tool_lp_search_competencies', args: { searchtext: searchText, @@ -253,7 +256,7 @@ define(['jquery', self._competencies = tree; - }).fail(Notification.exception); + }.bind(self)).fail(Notification.exception); }; /** @@ -263,7 +266,7 @@ define(['jquery', * @method _find */ Picker.prototype._find = function(selector) { - return $(self._popup.getContent()).find(selector); + return $(this._popup.getContent()).find(selector); }; /** @@ -274,7 +277,7 @@ define(['jquery', */ Picker.prototype._getFramework = function(fid) { var frm; - $.each(self._frameworks, function(i, f) { + $.each(this._frameworks, function(i, f) { if (f.id == fid) { frm = f; return false; @@ -290,7 +293,7 @@ define(['jquery', * @return {Promise} */ Picker.prototype._loadCompetencies = function() { - return self._fetchCompetencies(self._frameworkId, self._searchText); + return this._fetchCompetencies(this._frameworkId, this._searchText); }; /** @@ -300,7 +303,8 @@ define(['jquery', * @return {Promise} */ Picker.prototype._loadFrameworks = function() { - var promise; + var promise, + self = this; // Quit early because we already have the data. if (self._frameworks.length > 0) { @@ -338,7 +342,7 @@ define(['jquery', * @method on */ Picker.prototype.on = function(type, handler) { - self._eventNode.on(type, handler); + this._eventNode.on(type, handler); }; /** @@ -348,6 +352,7 @@ define(['jquery', * @return {Promise} */ Picker.prototype._preRender = function() { + var self = this; return self._loadFrameworks().then(function() { if (!self._frameworkId && self._frameworks.length > 0) { self._frameworkId = self._frameworks[0].id; @@ -360,7 +365,7 @@ define(['jquery', } return self._loadCompetencies(); - }); + }.bind(self)); }; /** @@ -370,10 +375,11 @@ define(['jquery', * @return {Promise} */ Picker.prototype._refresh = function() { + var self = this; return self._render().then(function(html) { self._find('[data-region="competencylinktree"]').replaceWith(html); self._afterRender(); - }); + }.bind(self)); }; /** @@ -383,6 +389,7 @@ define(['jquery', * @return {Promise} */ Picker.prototype._render = function() { + var self = this; return self._preRender().then(function() { if (!self._singleFramework) { @@ -404,7 +411,7 @@ define(['jquery', }; return Templates.render('tool_lp/competency_picker', context); - }); + }.bind(self)); }; /** @@ -415,11 +422,11 @@ define(['jquery', * @method _reset */ Picker.prototype._reset = function() { - self._competencies = []; - self._disallowedCompetencyIDs = []; - self._popup = null; - self._searchText = ''; - self._selectedCompetencies = []; + this._competencies = []; + this._disallowedCompetencyIDs = []; + this._popup = null; + this._searchText = ''; + this._selectedCompetencies = []; }; /** @@ -431,7 +438,7 @@ define(['jquery', * @method _setDisallowedCompetencyIDs */ Picker.prototype.setDisallowedCompetencyIDs = function(ids) { - self._disallowedCompetencyIDs = ids; + this._disallowedCompetencyIDs = ids; }; /** @@ -442,7 +449,7 @@ define(['jquery', * @method _reset */ Picker.prototype._trigger = function(type, data) { - self._eventNode.trigger(type, [data]); + this._eventNode.trigger(type, [data]); }; return /** @alias module:tool_lp/competencypicker */ Picker; diff --git a/admin/tool/lp/amd/src/competencypicker_user_plans.js b/admin/tool/lp/amd/src/competencypicker_user_plans.js new file mode 100644 index 00000000000..b18b5ab5549 --- /dev/null +++ b/admin/tool/lp/amd/src/competencypicker_user_plans.js @@ -0,0 +1,241 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Competency picker from user plans. + * + * To handle 'save' events use: picker.on('save'). + * + * This will receive a object with either a single 'competencyId', or an array in 'competencyIds' + * depending on the value of multiSelect. + * + * @package tool_lp + * @copyright 2015 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define(['jquery', + 'core/notification', + 'core/ajax', + 'core/templates', + 'core/str', + 'tool_lp/tree', + 'tool_lp/competencypicker' + ], + function($, Notification, Ajax, Templates, Str, Tree, PickerBase) { + + /** + * Competency picker in plan class. + * + * @param {Number|false} singlePlan The ID of the plan when limited to one. + * @param {String} pageContextIncludes One of 'children', 'parents', 'self'. + * @param {Boolean} multiSelect Support multi-select in the tree. + */ + var Picker = function(userId, singlePlan, multiSelect) { + PickerBase.prototype.constructor.apply(this, [1, false, 'self', multiSelect]); + this._userId = userId; + this._plans = []; + + if (singlePlan) { + this._planId = singlePlan; + this._singlePlan = true; + } + }; + Picker.prototype = Object.create(PickerBase.prototype); + + /** @type {Array} The list of plans fetched. */ + Picker.prototype._plans = null; + /** @type {Number} The current plan ID. */ + Picker.prototype._planId = null; + /** @type {Boolean} Whether we can browse plans or not. */ + Picker.prototype._singlePlan = false; + /** @type {Number} The user the plans belongs to. */ + Picker.prototype._userId = null; + + /** + * Hook to executed after the view is rendered. + * + * @method _afterRender + */ + Picker.prototype._afterRender = function() { + var self = this; + PickerBase.prototype._afterRender.apply(self, arguments); + + // Add listener for framework change. + if (!self._singlePlan) { + self._find('[data-action="chooseplan"]').change(function(e) { + self._planId = $(e.target).val(); + self._loadCompetencies().then(self._refresh.bind(self)); + }.bind(self)); + } + + }; + + /** + * Fetch the competencies. + * + * @param {Number} planId The planId. + * @param {String} searchText Limit the competencies to those matching the text. + * @method _fetchCompetencies + * @return {Promise} + */ + Picker.prototype._fetchCompetencies = function(planId, searchText) { + var self = this; + + return Ajax.call([ + { methodname: 'tool_lp_list_plan_competencies', args: { + id: planId + }} + ])[0].done(function(competencies) { + + // Expand the list of competencies into a fake tree. + var i, tree = [], comp; + for (i = 0; i < competencies.length; i++) { + comp = competencies[i].competency; + if (comp.shortname.toLowerCase().indexOf(searchText.toLowerCase()) < 0) { + continue; + } + comp.children = []; + comp.haschildren = 0; + tree.push(comp); + } + + self._competencies = tree; + + }).fail(Notification.exception); + }; + + /** + * Convenience method to get a plan object. + * + * @param {Number} id The plan ID. + * @return {Object|undefined} The plan. + * @method _getPlan + */ + Picker.prototype._getPlan = function(id) { + var plan; + $.each(this._plans, function(i, f) { + if (f.id == id) { + plan = f; + return false; + } + }); + return plan; + }; + + /** + * Load the competencies. + * + * @method _loadCompetencies + * @return {Promise} + */ + Picker.prototype._loadCompetencies = function() { + return this._fetchCompetencies(this._planId, this._searchText); + }; + + /** + * Load the plans. + * + * @method _loadPlans + * @return {Promise} + */ + Picker.prototype._loadPlans = function() { + var promise, + self = this; + + // Quit early because we already have the data. + if (self._plans.length > 0) { + return $.when(); + } + + if (self._singlePlan) { + promise = Ajax.call([ + { methodname: 'tool_lp_read_plan', args: { + id: this._planId + }} + ])[0].then(function(plan) { + return [plan]; + }); + } else { + promise = Ajax.call([ + { methodname: 'tool_lp_list_user_plans', args: { + userid: self._userId + }} + ])[0]; + } + + return promise.done(function(plans) { + self._plans = plans; + }).fail(Notification.exception); + }; + + /** + * Hook to executed before render. + * + * @method _preRender + * @return {Promise} + */ + Picker.prototype._preRender = function() { + var self = this; + return self._loadPlans().then(function() { + if (!self._planId && self._plans.length > 0) { + self._planId = self._plans[0].id; + } + + // We could not set a framework ID, that probably means there are no frameworks accessible. + if (!self._planId) { + self._plans = []; + return $.when(); + } + + return self._loadCompetencies(); + }.bind(self)); + }; + + /** + * Render the dialogue. + * + * @method _render + * @return {Promise} + */ + Picker.prototype._render = function() { + var self = this; + return self._preRender().then(function() { + + if (!self._singlePlan) { + $.each(self._plans, function(i, plan) { + if (plan.id == self._planId) { + plan.selected = true; + } else { + plan.selected = false; + } + }); + } + + var context = { + competencies: self._competencies, + plan: self._getPlan(self._planId), + plans: self._plans, + search: self._searchText, + singlePlan: self._singlePlan, + }; + + return Templates.render('tool_lp/competency_picker_user_plans', context); + }.bind(self)); + }; + + return /** @alias module:tool_lp/competencypicker_user_plans */ Picker; + +}); diff --git a/admin/tool/lp/amd/src/user_evidence_actions.js b/admin/tool/lp/amd/src/user_evidence_actions.js index 10d51c05744..d709cf992dd 100644 --- a/admin/tool/lp/amd/src/user_evidence_actions.js +++ b/admin/tool/lp/amd/src/user_evidence_actions.js @@ -26,8 +26,9 @@ define(['jquery', 'core/ajax', 'core/notification', 'core/str', - 'tool_lp/menubar'], - function($, templates, ajax, notification, str, Menubar) { + 'tool_lp/menubar', + 'tool_lp/competencypicker_user_plans'], + function($, templates, ajax, notification, str, Menubar, PickerUserPlans) { /** * UserEvidenceActions class. @@ -190,6 +191,100 @@ define(['jquery', this.deleteEvidence(data); }; + /** + * Link a competency and reload. + * + * @param {Object} evidenceData Evidence data from evidence node. + * @param {Number} competencyIds The competency IDs. + */ + UserEvidenceActions.prototype._doCreateUserEvidenceCompetency = function(evidenceData, competencyIds) { + var self = this, + calls = []; + + $.each(competencyIds, function(index, competencyId) { + calls.push({ + methodname: 'tool_lp_create_user_evidence_competency', + args: { + userevidenceid: evidenceData.id, + competencyid: competencyId, + } + }); + }); + + self._callAndRefresh(calls, evidenceData); + }; + + /** + * Create a user evidence competency. + * + * @param {Object} evidenceData Evidence data from evidence node. + */ + UserEvidenceActions.prototype.createUserEvidenceCompetency = function(evidenceData) { + var self = this, + picker = new PickerUserPlans(evidenceData.userid); + + picker.on('save', function(e, data) { + var competencyIds = data.competencyIds; + self._doCreateUserEvidenceCompetency(evidenceData, competencyIds); + }.bind(self)); + + picker.display(); + }; + + /** + * Create user evidence competency handler. + * + * @param {Event} e The event. + */ + UserEvidenceActions.prototype._createUserEvidenceCompetencyHandler = function(e) { + e.preventDefault(); + var data = this._findEvidenceData($(e.target)); + this.createUserEvidenceCompetency(data); + }; + + /** + * Remove a linked competency and reload. + * + * @param {Object} evidenceData Evidence data from evidence node. + * @param {Number} competencyId The competency ID. + */ + UserEvidenceActions.prototype._doDeleteUserEvidenceCompetency = function(evidenceData, competencyId) { + var self = this, + calls = []; + + calls.push({ + methodname: 'tool_lp_delete_user_evidence_competency', + args: { + userevidenceid: evidenceData.id, + competencyid: competencyId, + } + }); + + self._callAndRefresh(calls, evidenceData); + }; + + /** + * Delete a user evidence competency. + * + * @param {Object} evidenceData Evidence data from evidence node. + * @param {Number} competencyId The competency ID. + */ + UserEvidenceActions.prototype.deleteUserEvidenceCompetency = function(evidenceData, competencyId) { + this._doDeleteUserEvidenceCompetency(evidenceData, competencyId); + }; + + /** + * Delete user evidence competency handler. + * + * @param {Event} e The event. + */ + UserEvidenceActions.prototype._deleteUserEvidenceCompetencyHandler = function(e) { + var data = this._findEvidenceData($(e.currentTarget)), + competencyId = $(e.currentTarget).data('id'); + e.preventDefault(); + this.deleteUserEvidenceCompetency(data, competencyId); + }; + /** * Find the evidence data from the evidence node. * @@ -221,6 +316,7 @@ define(['jquery', var self = this; Menubar.enhance(selector, { '[data-action="user-evidence-delete"]': self._deleteEvidenceHandler.bind(self), + '[data-action="link-competency"]': self._createUserEvidenceCompetencyHandler.bind(self), }); }; @@ -235,6 +331,8 @@ define(['jquery', self = this; wrapper.find('[data-action="user-evidence-delete"]').click(self._deleteEvidenceHandler.bind(self)); + wrapper.find('[data-action="link-competency"]').click(self._createUserEvidenceCompetencyHandler.bind(self)); + wrapper.find('[data-action="delete-competency-link"]').click(self._deleteUserEvidenceCompetencyHandler.bind(self)); }; return /** @alias module:tool_lp/user_evidence_actions */ UserEvidenceActions; diff --git a/admin/tool/lp/classes/api.php b/admin/tool/lp/classes/api.php index 51ca0829600..be9abaf845a 100644 --- a/admin/tool/lp/classes/api.php +++ b/admin/tool/lp/classes/api.php @@ -1418,7 +1418,7 @@ class api { $params['statusdraft'] = plan::STATUS_DRAFT; } - return plan::get_records_select($select, $params, 'name DESC'); + return plan::get_records_select($select, $params, 'name ASC'); } /** @@ -2151,10 +2151,21 @@ class api { throw new required_capability_exception($context, 'tool/lp:userevidencemanage', 'nopermissions', ''); } + // Delete the user evidence. $userevidence->delete(); + + // Delete associated files. $fs = get_file_storage(); $fs->delete_area_files($context->id, 'tool_lp', 'userevidence', $id); + // Delete relation between evidence and competencies. + $userevidence->set_id($id); // Restore the ID to fully mock the object. + $competencies = user_evidence_competency::get_competencies_by_userevidenceid($id); + foreach ($competencies as $competency) { + static::delete_user_evidence_competency($userevidence, $competency->get_id()); + } + $userevidence->set_id(0); // Restore the object. + return true; } @@ -2174,6 +2185,101 @@ class api { return $evidence; } + /** + * Link a user evidence with a competency. + * + * @param user_evidence|int $userevidenceorid User evidence or its ID. + * @param int $competencyid Competency ID. + * @return user_evidence_competency + */ + public static function create_user_evidence_competency($userevidenceorid, $competencyid) { + global $USER; + + $userevidence = $userevidenceorid; + if (!is_object($userevidence)) { + $userevidence = self::read_user_evidence($userevidence); + } + + // Perform user evidence capability checks. + if (!$userevidence->can_manage()) { + $context = $userevidence->get_context(); + throw new required_capability_exception($context, 'tool/lp:userevidencemanage', 'nopermissions', ''); + } + + // Perform competency capability checks. + $competency = self::read_competency($competencyid); + + // Get (and create) the relation. + $relation = user_evidence_competency::get_relation($userevidence->get_id(), $competency->get_id()); + if (!$relation->get_id()) { + $relation->create(); + + $link = new moodle_url('/admin/tool/lp/user_evidence.php', array('id' => $userevidence->get_id())); + self::add_evidence( + $userevidence->get_userid(), + $competency, + $userevidence->get_context(), + evidence::ACTION_LOG, + 'evidence_evidenceofpriorlearninglinked', + 'tool_lp', + $userevidence->get_name(), + false, + $link->out(false), + null, + $USER->id + ); + } + + return $relation; + } + + /** + * Delete a relationship between a user evidence and a competency. + * + * @param user_evidence|int $userevidenceorid User evidence or its ID. + * @param int $competencyid Competency ID. + * @return bool + */ + public static function delete_user_evidence_competency($userevidenceorid, $competencyid) { + global $USER; + + $userevidence = $userevidenceorid; + if (!is_object($userevidence)) { + $userevidence = self::read_user_evidence($userevidence); + } + + // Perform user evidence capability checks. + if (!$userevidence->can_manage()) { + $context = $userevidence->get_context(); + throw new required_capability_exception($context, 'tool/lp:userevidencemanage', 'nopermissions', ''); + } + + // Get (and delete) the relation. + $relation = user_evidence_competency::get_relation($userevidence->get_id(), $competencyid); + if (!$relation->get_id()) { + return true; + } + + $success = $relation->delete(); + if ($success) { + self::add_evidence( + $userevidence->get_userid(), + $competencyid, + $userevidence->get_context(), + evidence::ACTION_LOG, + 'evidence_evidenceofpriorlearningunlinked', + 'tool_lp', + $userevidence->get_name(), + false, + null, + null, + $USER->id + ); + } + + return $success; + } + /** * Recursively duplicate competencies from a tree, we start duplicating from parents to children to have a correct path. * This method does not copy the related competencies. @@ -2274,7 +2380,7 @@ class api { * * @param int $userid The user id for which evidence is added. * @param int $competencyid The competency, or its id for which evidence is added. - * @param int $contextid The context in which the evidence took place. + * @param context|int $contextorid The context in which the evidence took place. * @param int $action The type of action to take on the competency. \tool_lp\evidence::ACTION_*. * @param string $descidentifier The strings identifier. * @param string $desccomponent The strings component. @@ -2289,7 +2395,7 @@ class api { */ public static function add_evidence($userid, $competencyorid, - $contextid, + $contextorid, $action, $descidentifier, $desccomponent, @@ -2307,6 +2413,7 @@ class api { $competency = $competencyid; $competencyid = $competency->get_id(); } + $contextid = is_object($contextorid) ? $contextorid->id : $contextorid; $setucgrade = false; $ucgrade = null; $ucproficiency = null; diff --git a/admin/tool/lp/classes/external.php b/admin/tool/lp/classes/external.php index 82a7001c5ee..e500f5a92de 100644 --- a/admin/tool/lp/classes/external.php +++ b/admin/tool/lp/classes/external.php @@ -48,6 +48,7 @@ use tool_lp\external\user_summary_exporter; use tool_lp\external\user_competency_exporter; use tool_lp\external\user_competency_plan_exporter; use tool_lp\external\user_evidence_exporter; +use tool_lp\external\user_evidence_competency_exporter; use tool_lp\external\competency_exporter; use tool_lp\external\course_competency_exporter; use tool_lp\external\course_summary_exporter; @@ -3195,11 +3196,59 @@ class external extends external_api { ); } - /** + /** * Returns description of external function parameters. * * @return \external_function_parameters */ + public static function list_user_plans_parameters() { + return new external_function_parameters(array( + 'userid' => new external_value(PARAM_INT, 'The user ID'), + )); + } + + /** + * External function list_user_plans. + * + * @param int $userid The user ID. + * @return boolean + */ + public static function list_user_plans($userid) { + global $PAGE; + $params = self::validate_parameters(self::list_user_plans_parameters(), array( + 'userid' => $userid + )); + + $context = context_user::instance($params['userid']); + self::validate_context($context); + $output = $PAGE->get_renderer('tool_lp'); + + $response = array(); + $plans = api::list_user_plans($params['userid']); + foreach ($plans as $plan) { + $exporter = new plan_exporter($plan, array('template' => $plan->get_template())); + $response[] = $exporter->export($output); + } + + return $response; + } + + /** + * Returns description of external function result value. + * + * @return \external_function_parameters + */ + public static function list_user_plans_returns() { + return new external_multiple_structure( + plan_exporter::get_read_structure() + ); + } + + /** + * Returns description of external function parameters. + * + * @return \external_description + */ public static function read_user_evidence_parameters() { return new external_function_parameters(array( 'id' => new external_value(PARAM_INT, 'The user evidence ID.'), @@ -3221,8 +3270,8 @@ class external extends external_api { self::validate_context($context); $output = $PAGE->get_renderer('tool_lp'); - // TODO MDL-51869. - $exporter = new user_evidence_exporter($userevidence, array('context' => $context, 'competencies' => array())); + $exporter = new user_evidence_exporter($userevidence, array('context' => $context, + 'competencies' => $userevidence->get_competencies())); return $exporter->export($output); } @@ -3270,7 +3319,6 @@ class external extends external_api { return new external_value(PARAM_BOOL, 'True if the delete was successful'); } - /** * Returns description of external function parameters. * @@ -3320,6 +3368,130 @@ class external extends external_api { )); } + /** + * Returns description of external function parameters. + * + * @return \external_function_parameters + */ + public static function data_for_user_evidence_page_parameters() { + return new external_function_parameters(array( + 'id' => new external_value(PARAM_INT, 'The user evidence ID') + )); + } + + /** + * Loads the data required to render the user_evidence_page template. + * + * @param int $userid User id. + * @return boolean + */ + public static function data_for_user_evidence_page($id) { + global $PAGE; + $params = self::validate_parameters(self::data_for_user_evidence_page_parameters(), + array('id' => $id)); + + $userevidence = api::read_user_evidence($id); + self::validate_context($userevidence->get_context()); + $output = $PAGE->get_renderer('tool_lp'); + + $renderable = new \tool_lp\output\user_evidence_page($userevidence); + return $renderable->export_for_template($output); + } + + /** + * Returns description of external function result value. + * + * @return \external_description + */ + public static function data_for_user_evidence_page_returns() { + return new external_single_structure(array( + 'userevidence' => user_evidence_exporter::get_read_structure(), + 'pluginbaseurl' => new external_value(PARAM_LOCALURL, 'Url to the tool_lp plugin folder on this Moodle site'), + )); + } + + /** + * Returns description of external function parameters. + * + * @return \external_function_parameters + */ + public static function create_user_evidence_competency_parameters() { + return new external_function_parameters(array( + 'userevidenceid' => new external_value(PARAM_INT, 'The user evidence ID.'), + 'competencyid' => new external_value(PARAM_INT, 'The competency ID.'), + )); + } + + /** + * Delete a user evidence competency relationship. + * + * @param int $userevidenceid The user evidence id. + * @param int $competencyid The competency id. + * @return boolean + */ + public static function create_user_evidence_competency($userevidenceid, $competencyid) { + global $PAGE; + $params = self::validate_parameters(self::create_user_evidence_competency_parameters(), array( + 'userevidenceid' => $userevidenceid, + 'competencyid' => $competencyid, + )); + + $userevidence = api::read_user_evidence($params['userevidenceid']); + self::validate_context($userevidence->get_context()); + + $relation = api::create_user_evidence_competency($userevidence, $competencyid); + $exporter = new user_evidence_competency_exporter($relation); + return $exporter->export($PAGE->get_renderer('tool_lp')); + } + + /** + * Returns description of external function result value. + * + * @return \external_description + */ + public static function create_user_evidence_competency_returns() { + return user_evidence_competency_exporter::get_read_structure(); + } + + /** + * Returns description of external function parameters. + * + * @return \external_function_parameters + */ + public static function delete_user_evidence_competency_parameters() { + return new external_function_parameters(array( + 'userevidenceid' => new external_value(PARAM_INT, 'The user evidence ID.'), + 'competencyid' => new external_value(PARAM_INT, 'The competency ID.'), + )); + } + + /** + * Delete a user evidence competency relationship. + * + * @param int $userevidenceid The user evidence id. + * @param int $competencyid The competency id. + * @return boolean + */ + public static function delete_user_evidence_competency($userevidenceid, $competencyid) { + $params = self::validate_parameters(self::delete_user_evidence_competency_parameters(), array( + 'userevidenceid' => $userevidenceid, + 'competencyid' => $competencyid, + )); + + $userevidence = api::read_user_evidence($params['userevidenceid']); + self::validate_context($userevidence->get_context()); + + return api::delete_user_evidence_competency($userevidence, $params['competencyid']); + } + + /** + * Returns description of external function result value. + * + * @return \external_description + */ + public static function delete_user_evidence_competency_returns() { + return new external_value(PARAM_BOOL, 'True if the delete was successful'); + } /** * Returns the description of the get_scale_values() parameters. diff --git a/admin/tool/lp/classes/external/stored_file_exporter.php b/admin/tool/lp/classes/external/stored_file_exporter.php index 1b10a1a30cb..696d5b3f8cd 100644 --- a/admin/tool/lp/classes/external/stored_file_exporter.php +++ b/admin/tool/lp/classes/external/stored_file_exporter.php @@ -162,7 +162,7 @@ class stored_file_exporter extends exporter { 'filenameshort' => $filenameshort, 'filesizeformatted' => display_size((int) $this->file->get_filesize()), 'icon' => $icon, - 'iconurl' => $iconurl, + 'iconurl' => $iconurl->out(false), 'url' => $url->out(false), 'timecreatedformatted' => userdate($this->file->get_timecreated()), 'timemodifiedformatted' => userdate($this->file->get_timemodified()), diff --git a/admin/tool/lp/classes/external/user_evidence_competency_exporter.php b/admin/tool/lp/classes/external/user_evidence_competency_exporter.php new file mode 100644 index 00000000000..f2a103a6cba --- /dev/null +++ b/admin/tool/lp/classes/external/user_evidence_competency_exporter.php @@ -0,0 +1,41 @@ +. + +/** + * User evidence competency exporter. + * + * @package tool_lp + * @copyright 2015 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_lp\external; +defined('MOODLE_INTERNAL') || die(); + +/** + * User evidence competency exporter class. + * + * @package tool_lp + * @copyright 2015 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_evidence_competency_exporter extends persistent_exporter { + + protected static function define_class() { + return 'tool_lp\\user_evidence_competency'; + } + +} diff --git a/admin/tool/lp/classes/external/user_evidence_exporter.php b/admin/tool/lp/classes/external/user_evidence_exporter.php index f7c5591e62c..1cd220fc23d 100644 --- a/admin/tool/lp/classes/external/user_evidence_exporter.php +++ b/admin/tool/lp/classes/external/user_evidence_exporter.php @@ -44,6 +44,9 @@ class user_evidence_exporter extends persistent_exporter { 'canmanage' => array( 'type' => PARAM_BOOL ), + 'competencycount' => array( + 'type' => PARAM_INT + ), 'competencies' => array( 'type' => competency_exporter::read_properties_definition(), 'multiple' => true @@ -72,11 +75,16 @@ class user_evidence_exporter extends persistent_exporter { } protected function get_other_values(renderer_base $output) { + $contextcache = array(); $competencies = array(); foreach ($this->related['competencies'] as $competency) { - // TODO MDL-51869. - $compexporter = new competency_exporter($competency); + if (!isset($contextcache[$competency->get_competencyframeworkid()])) { + $contextcache[$competency->get_competencyframeworkid()] = $competency->get_context(); + } + $context = $contextcache[$competency->get_competencyframeworkid()]; + + $compexporter = new competency_exporter($competency, array('context' => $context)); $competencies[] = $compexporter->export($output); } @@ -99,6 +107,7 @@ class user_evidence_exporter extends persistent_exporter { $values = array( 'canmanage' => $this->persistent->can_manage(), + 'competencycount' => count($competencies), 'competencies' => $competencies, 'filecount' => count($files), 'files' => $files, diff --git a/admin/tool/lp/classes/output/user_evidence_list_page.php b/admin/tool/lp/classes/output/user_evidence_list_page.php index 3013301c804..73a4fcdeeaf 100644 --- a/admin/tool/lp/classes/output/user_evidence_list_page.php +++ b/admin/tool/lp/classes/output/user_evidence_list_page.php @@ -95,8 +95,7 @@ class user_evidence_list_page implements renderable, templatable { foreach ($this->evidence as $evidence) { $evidenceexporter = new user_evidence_exporter($evidence, array( 'context' => $this->context, - // TODO MDL-51869. - 'competencies' => array() + 'competencies' => $evidence->get_competencies() )); $record = $evidenceexporter->export($output); $data->evidence[] = $record; diff --git a/admin/tool/lp/classes/output/user_evidence_page.php b/admin/tool/lp/classes/output/user_evidence_page.php index 09707da6b1b..54e53dacd25 100644 --- a/admin/tool/lp/classes/output/user_evidence_page.php +++ b/admin/tool/lp/classes/output/user_evidence_page.php @@ -66,8 +66,7 @@ class user_evidence_page implements renderable, templatable { $data = new stdClass(); $evidenceexporter = new user_evidence_exporter($this->userevidence, array( 'context' => $this->context, - // TODO MDL-51869. - 'competencies' => array() + 'competencies' => $this->userevidence->get_competencies() )); $data->userevidence = $evidenceexporter->export($output); $data->pluginbaseurl = (new moodle_url('/admin/tool/lp'))->out(true); diff --git a/admin/tool/lp/classes/user_evidence.php b/admin/tool/lp/classes/user_evidence.php index 85f44038e3e..61e19d8ec16 100644 --- a/admin/tool/lp/classes/user_evidence.php +++ b/admin/tool/lp/classes/user_evidence.php @@ -96,6 +96,13 @@ class user_evidence extends persistent { return context_user::instance($this->get_userid()); } + /** + * Get link competencies. + */ + public function get_competencies() { + return user_evidence_competency::get_competencies_by_userevidenceid($this->get_id()); + } + /** * Return the files associated with this evidence. * diff --git a/admin/tool/lp/classes/user_evidence_competency.php b/admin/tool/lp/classes/user_evidence_competency.php new file mode 100644 index 00000000000..f4abcfb9fef --- /dev/null +++ b/admin/tool/lp/classes/user_evidence_competency.php @@ -0,0 +1,134 @@ +. + +/** + * User evidence competency persistent. + * + * This represent the many to many relationship between evidence of prior + * learning and competencies. + * + * @package tool_lp + * @copyright 2015 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_lp; +defined('MOODLE_INTERNAL') || die(); + +use stdClass; + +/** + * User evidence competency persistent class. + * + * @package tool_lp + * @copyright 2015 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_evidence_competency extends persistent { + + const TABLE = 'tool_lp_user_evidence_comp'; + + /** + * Return the definition of the properties of this model. + * + * @return array + */ + protected static function define_properties() { + return array( + 'userevidenceid' => array( + 'type' => PARAM_INT + ), + 'competencyid' => array( + 'type' => PARAM_INT, + ), + ); + } + + /** + * Validate competency ID. + * + * @param int $value ID. + * @return true|lang_string + */ + protected function validate_competencyid($value) { + if (!competency::record_exists($value)) { + return new lang_string('invaliddata', 'error'); + } + return true; + } + + /** + * Validate user evidence ID. + * + * @param int $value ID. + * @return true|lang_string + */ + protected function validate_userevidenceid($value) { + if (!user_evidence::record_exists($value)) { + return new lang_string('invaliddata', 'error'); + } + return true; + } + + /** + * Get competencies by user evidence ID. + * + * @param int $userevidenceid The user evidence ID. + * @return competency[] + */ + public static function get_competencies_by_userevidenceid($userevidenceid) { + global $DB; + $sql = "SELECT c.* + FROM {" . self::TABLE . "} uec + JOIN {" . competency::TABLE . "} c + ON uec.userevidenceid = ? + AND uec.competencyid = c.id + ORDER BY c.shortname"; + $competencies = array(); + $records = $DB->get_recordset_sql($sql, array($userevidenceid)); + foreach ($records as $record) { + $competencies[] = new competency(0, $record); + } + $records->close(); + return $competencies; + } + + /** + * Get a relation. + * + * This does not perform any validation on the data passed. If the relation exists in the database + * then it is loaded in a the model, if not then it is up to the developer to save the model. + * + * @param int $userevidenceid + * @param int $competencyid + * @return template_cohort + */ + public static function get_relation($userevidenceid, $competencyid) { + global $DB; + + $params = array( + 'userevidenceid' => $userevidenceid, + 'competencyid' => $competencyid + ); + + $relation = new static(null, (object) $params); + if ($record = $DB->get_record(static::TABLE, $params)) { + $relation->from_record($record); + } + + return $relation; + } + +} diff --git a/admin/tool/lp/db/install.xml b/admin/tool/lp/db/install.xml index 53c7f945002..3bee0f7de27 100755 --- a/admin/tool/lp/db/install.xml +++ b/admin/tool/lp/db/install.xml @@ -1,5 +1,5 @@ - @@ -261,5 +261,22 @@ + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/admin/tool/lp/db/services.php b/admin/tool/lp/db/services.php index 2975328d56a..15183426922 100644 --- a/admin/tool/lp/db/services.php +++ b/admin/tool/lp/db/services.php @@ -489,6 +489,15 @@ $functions = array( 'capabilities' => 'tool/lp:planmanage', 'ajax' => true, ), + 'tool_lp_list_user_plans' => array( + 'classname' => 'tool_lp\external', + 'methodname' => 'list_user_plans', + 'classpath' => '', + 'description' => 'List a user\'s learning plans.', + 'type' => 'read', + 'capabilities' => 'tool/lp:planviewown', + 'ajax' => true, + ), 'tool_lp_data_for_plans_page' => array( 'classname' => 'tool_lp\external', 'methodname' => 'data_for_plans_page', @@ -626,5 +635,32 @@ $functions = array( 'capabilities' => 'tool/lp:userevidenceread', 'ajax' => true, ), + 'tool_lp_data_for_user_evidence_page' => array( + 'classname' => 'tool_lp\external', + 'methodname' => 'data_for_user_evidence_page', + 'classpath' => '', + 'description' => 'Load the data for the user evidence page template', + 'type' => 'read', + 'capabilities' => 'tool/lp:userevidenceread', + 'ajax' => true, + ), + 'tool_lp_create_user_evidence_competency' => array( + 'classname' => 'tool_lp\external', + 'methodname' => 'create_user_evidence_competency', + 'classpath' => '', + 'description' => 'Create an evidence of prior learning relationship with a competency.', + 'type' => 'read', + 'capabilities' => 'tool/lp:userevidencemanageown, tool/lp:competencyread', + 'ajax' => true, + ), + 'tool_lp_delete_user_evidence_competency' => array( + 'classname' => 'tool_lp\external', + 'methodname' => 'delete_user_evidence_competency', + 'classpath' => '', + 'description' => 'Delete an evidence of prior learning relationship with a competency.', + 'type' => 'write', + 'capabilities' => 'tool/lp:userevidencemanageown', + 'ajax' => true, + ), ); diff --git a/admin/tool/lp/db/upgrade.php b/admin/tool/lp/db/upgrade.php index b45abf81655..b6ae26109a8 100644 --- a/admin/tool/lp/db/upgrade.php +++ b/admin/tool/lp/db/upgrade.php @@ -607,6 +607,34 @@ function xmldb_tool_lp_upgrade($oldversion) { upgrade_plugin_savepoint(true, 2015111027, 'tool', 'lp'); } + if ($oldversion < 2015111029) { + + // Define table tool_lp_user_evidence_comp to be created. + $table = new xmldb_table('tool_lp_user_evidence_comp'); + + // Adding fields to table tool_lp_user_evidence_comp. + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); + $table->add_field('userevidenceid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); + $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); + $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); + $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); + $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); + + // Adding keys to table tool_lp_user_evidence_comp. + $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); + + // Adding indexes to table tool_lp_user_evidence_comp. + $table->add_index('userevidenceid', XMLDB_INDEX_NOTUNIQUE, array('userevidenceid')); + $table->add_index('userevidencecompids', XMLDB_INDEX_UNIQUE, array('userevidenceid', 'competencyid')); + + // Conditionally launch create table for tool_lp_user_evidence_comp. + if (!$dbman->table_exists($table)) { + $dbman->create_table($table); + } + + // Lp savepoint reached. + upgrade_plugin_savepoint(true, 2015111029, 'tool', 'lp'); + } return true; } diff --git a/admin/tool/lp/lang/en/tool_lp.php b/admin/tool/lp/lang/en/tool_lp.php index 47af094b4ce..5435ed4bba1 100644 --- a/admin/tool/lp/lang/en/tool_lp.php +++ b/admin/tool/lp/lang/en/tool_lp.php @@ -85,6 +85,8 @@ $string['editthisplan'] = 'Edit this learning plan'; $string['editthisuserevidence'] = 'Edit this evidence'; $string['edituserevidence'] = 'Edit evidence'; $string['evidence_coursecompleted'] = 'The course \'{$a}\' was completed.'; +$string['evidence_evidenceofpriorlearninglinked'] = 'The evidence of prior learning \'{$a}\' was linked.'; +$string['evidence_evidenceofpriorlearningunlinked'] = 'The evidence of prior learning \'{$a}\' was unlinked.'; $string['errorcannotsetduedateinthepast'] = 'The due date cannot be set in the past.'; $string['errorcannotchangeapastduedate'] = 'The due date has passed, it cannot be changed.'; $string['errornocompetency'] = '{$a} competency can not be found'; @@ -106,6 +108,7 @@ $string['learningplancompetencies'] = 'Learning plan competencies'; $string['learningplans'] = 'Learning plans'; $string['levela'] = 'Level {$a}'; $string['linkcompetency'] = 'Link competency'; +$string['linkcompetencies'] = 'Link competencies'; $string['linkcoursecompetencies'] = 'Link course competencies'; $string['linkedcompetencies'] = 'Linked competencies'; $string['linkedcourses'] = 'Linked courses:'; diff --git a/admin/tool/lp/styles.css b/admin/tool/lp/styles.css index 0eb6d02e498..3d3f1ba6d90 100644 --- a/admin/tool/lp/styles.css +++ b/admin/tool/lp/styles.css @@ -111,6 +111,10 @@ /** Styles required for menubar js */ +.tool-lp-menu { + margin: 0; +} + .tool-lp-menu li { float: left; display: inline; @@ -170,10 +174,13 @@ input[type="checkbox"].tool_lp_scale_proficient { margin: 10px 20px; list-style: none; } +.user-evidence-competencies, .user-evidence-documents li { margin-bottom: 5px; word-break: break-all; } +[data-region="user-evidence-list"] .user-evidence-competencies, [data-region="user-evidence-list"] .user-evidence-documents { margin: 0; + list-style: none; } diff --git a/admin/tool/lp/templates/competency_picker_user_plans.mustache b/admin/tool/lp/templates/competency_picker_user_plans.mustache new file mode 100644 index 00000000000..1e052b94172 --- /dev/null +++ b/admin/tool/lp/templates/competency_picker_user_plans.mustache @@ -0,0 +1,34 @@ +
+{{^singlePlan}} +

{{#str}}learningplans, tool_lp{{/str}}

+ +{{/singlePlan}} + +

{{#str}}locatecompetency, tool_lp{{/str}}

+ +
+ + + +
+ +
    +
  • {{plan.name}} +
      + {{#competencies}} + {{> tool_lp/competencies_tree }} + {{/competencies}} +
    +
  • +
+ +
+ + +
+ +
diff --git a/admin/tool/lp/templates/user_evidence_list_page.mustache b/admin/tool/lp/templates/user_evidence_list_page.mustache index 7dca1c6cc16..33e8480f27e 100644 --- a/admin/tool/lp/templates/user_evidence_list_page.mustache +++ b/admin/tool/lp/templates/user_evidence_list_page.mustache @@ -66,12 +66,18 @@ {{/hasurlorfiles}} - {{^competencies}} + {{^competencycount}} - - {{/competencies}} - {{#competencies}} - {{! TODO MDL-51869 }} - {{/competencies}} + {{/competencycount}} + {{#competencycount}} +
    + {{#competencies}} +
  • + {{shortname}} {{idnumber}} +
  • + {{/competencies}} +
+ {{/competencycount}} {{#canmanage}} @@ -85,6 +91,11 @@ {{#pix}}t/edit{{/pix}} {{#str}}editthisuserevidence, tool_lp{{/str}} +
  • + + {{#pix}}t/add{{/pix}} {{#str}}linkcompetencies, tool_lp{{/str}} + +
  • {{#pix}}t/delete{{/pix}} {{#str}}deletethisuserevidence, tool_lp{{/str}} diff --git a/admin/tool/lp/templates/user_evidence_page.mustache b/admin/tool/lp/templates/user_evidence_page.mustache index 9477010e549..ce7d849089c 100644 --- a/admin/tool/lp/templates/user_evidence_page.mustache +++ b/admin/tool/lp/templates/user_evidence_page.mustache @@ -18,7 +18,7 @@ User evidence page template. Data attributes required for JS: - * data-action = add + * data-action = link-competency * data-action = delete-competency-link * data-region = user-evidence-page * data-id = user evidence ID, or competency ID @@ -29,7 +29,7 @@ * pluginbaseurl - The plugin base URL }} {{#userevidence}} -
    + @@ -70,13 +70,13 @@ {{shortname}} - {{#canmanage}} + {{#userevidence.canmanage}} - {{/canmanage}} + {{/userevidence.canmanage}} {{/competencies}} @@ -85,7 +85,7 @@
    {{#canmanage}} - + {{/canmanage}}
    @@ -97,7 +97,7 @@ require(['tool_lp/user_evidence_actions'], function(UserEvidenceActions) { var uea = new UserEvidenceActions('evidence'); - planActions.registerEvents(); + uea.registerEvents(); }); {{/js}} diff --git a/admin/tool/lp/version.php b/admin/tool/lp/version.php index 88c291a46d7..e2c16523970 100644 --- a/admin/tool/lp/version.php +++ b/admin/tool/lp/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2015111028; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2015111029; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2014110400; // Requires this Moodle version. $plugin->component = 'tool_lp'; // Full name of the plugin (used for diagnostics).