From d17cbbfbad2cb050b43e9518b76c339e4924e97c Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Tue, 9 Feb 2016 12:49:42 +0800 Subject: [PATCH] MDL-52691 tool_lp: Add note support to competency rating --- admin/tool/lp/amd/build/grade_dialogue.min.js | 1 + .../build/grade_user_competency_inline.min.js | 2 +- admin/tool/lp/amd/src/grade_dialogue.js | 166 +++++++++++++++++ .../amd/src/grade_user_competency_inline.js | 172 +++++++----------- admin/tool/lp/classes/api.php | 23 ++- admin/tool/lp/classes/evidence.php | 5 + admin/tool/lp/classes/external.php | 51 ++++-- admin/tool/lp/db/install.xml | 3 +- admin/tool/lp/db/upgrade.php | 15 ++ admin/tool/lp/lang/en/tool_lp.php | 1 + admin/tool/lp/styles.css | 7 + .../lp/templates/competency_grader.mustache | 31 ++++ .../lp/templates/evidence_summary.mustache | 3 + .../user_competency_summary.mustache | 21 +-- ...user_competency_summary_in_course.mustache | 22 +-- .../user_competency_summary_in_plan.mustache | 30 +-- admin/tool/lp/tests/api_test.php | 3 +- admin/tool/lp/tests/externallib_test.php | 3 +- admin/tool/lp/version.php | 2 +- 19 files changed, 368 insertions(+), 193 deletions(-) create mode 100644 admin/tool/lp/amd/build/grade_dialogue.min.js create mode 100644 admin/tool/lp/amd/src/grade_dialogue.js create mode 100644 admin/tool/lp/templates/competency_grader.mustache diff --git a/admin/tool/lp/amd/build/grade_dialogue.min.js b/admin/tool/lp/amd/build/grade_dialogue.min.js new file mode 100644 index 00000000000..58d825f56c4 --- /dev/null +++ b/admin/tool/lp/amd/build/grade_dialogue.min.js @@ -0,0 +1 @@ +define(["jquery","core/notification","core/templates","tool_lp/dialogue","tool_lp/event_base","core/str"],function(a,b,c,d,e,f){var g=function(a,b,c){e.prototype.constructor.apply(this,[]),this._ratingOptions=a,this._canGrade=b||!1,this._canSuggest=c||!1};return g.prototype=Object.create(e.prototype),g.prototype._popup=null,g.prototype._canGrade=!1,g.prototype._canSuggest=!1,g.prototype._ratingOptions=null,g.prototype._afterRender=function(){var b=this._find('[data-action="rate"]'),c=this._find('[data-action="suggest"]'),d=this._find('[name="rating"]'),e=this._find('[name="comment"]');this._find('[data-action="cancel"]').click(function(a){a.preventDefault(),this._trigger("cancelled"),this.close()}.bind(this)),d.change(function(){var d=a(this);d.val()?(b.prop("disabled",!1),c.prop("disabled",!1)):(b.prop("disabled",!0),c.prop("disabled",!0))}).change(),b.click(function(a){a.preventDefault();var b=d.val();b&&(this._trigger("rated",{rating:b,note:e.val()}),this.close())}.bind(this)),c.click(function(a){a.preventDefault();var b=d.val();b&&(this._trigger("suggested",{rating:b,note:e.val()}),this.close())}.bind(this))},g.prototype.close=function(){this._popup.close(),this._popup=null},g.prototype.display=function(){return this._render().then(function(a){return f.get_string("rate","tool_lp").then(function(b){this._popup=new d(b,a,this._afterRender.bind(this))}.bind(this))}.bind(this)).fail(b.exception)},g.prototype._find=function(b){return a(this._popup.getContent()).find(b)},g.prototype._render=function(){var a={cangrade:this._canGrade,cansuggest:this._canSuggest,ratings:this._ratingOptions};return c.render("tool_lp/competency_grader",a)},g}); \ No newline at end of file diff --git a/admin/tool/lp/amd/build/grade_user_competency_inline.min.js b/admin/tool/lp/amd/build/grade_user_competency_inline.min.js index 25919241879..58dd21e425f 100644 --- a/admin/tool/lp/amd/build/grade_user_competency_inline.min.js +++ b/admin/tool/lp/amd/build/grade_user_competency_inline.min.js @@ -1 +1 @@ -define(["jquery","core/notification","core/ajax","core/log"],function(a,b,c,d){var e=function(a,b,c,d,e,f,g){this._formId=a,this._scaleConfig=b,this._competencyId=c,this._userId=d,this._planId=e,this._courseId=f,this._valid=!0,this._chooseStr=g,this._buildSelect(),this._addListeners(),this._planId?(this._methodName="tool_lp_grade_competency_in_plan",this._args={competencyid:this._competencyId,planid:this._planId}):this._courseId?(this._methodName="tool_lp_grade_competency_in_course",this._args={competencyid:this._competencyId,courseid:this._courseId,userid:this._userId}):(this._methodName="tool_lp_grade_competency",this._args={userid:this._userId,competencyid:this._competencyId})};return e.prototype._buildSelect=function(){var b=1,c=a("");for(c.text(this._chooseStr),c.attr("value",""),a(document.getElementById(this._formId)).find("select").append(c),b=1;b");e.text(d.name),e.attr("value",d.id),a(document.getElementById(this._formId)).find("select").append(e)}},e.prototype._handleGrade=function(d){var e=this,f=a(document.getElementById(this._formId)).find("select").val();if(d.preventDefault(),this._valid&&f){var g=this._args;g.grade=f,g.override=!0,c.call([{methodname:this._methodName,args:g,done:function(a){e._trigger("competencyupdated",{args:g,evidence:a})},fail:b.exception}])}},e.prototype._handleSuggest=function(d){var e=this,f=a(document.getElementById(this._formId)).find("select").val();if(d.preventDefault(),this._valid&&f){var g=this._args;g.grade=f,g.override=!1,c.call([{methodname:this._methodName,args:g,done:function(a){e._trigger("competencyupdated",{args:g,evidence:a})},fail:b.exception}])}},e.prototype._addListeners=function(){var b=this,c=a(document.getElementById(this._formId)),d=c.find('[data-action="grade"]');d.on("click",function(a){b._handleGrade.call(b,a)});var e=c.find('[data-action="suggest"]');e.on("click",function(a){b._handleSuggest.call(b,a)})},e.prototype._trigger=function(c,d){return"competencyupdated"!=c&&b.exception("Invalid event name:"+c),a(document.getElementById(this._formId)).trigger(c,d),this},e.prototype.on=function(c,d){return"competencyupdated"!=c&&b.exception("Invalid event name:"+c),a(document.getElementById(this._formId)).on(c,d),this},e.prototype._formId=null,e.prototype._scaleConfig=null,e.prototype._competencyId=null,e.prototype._userId=null,e.prototype._planId=null,e.prototype._courseId=null,e.prototype._valid=null,e}); \ No newline at end of file +define(["jquery","core/notification","core/ajax","core/log","tool_lp/grade_dialogue","tool_lp/event_base"],function(a,b,c,d,e,f){var g=function(b,c,d,e,g,h,i,j,k){f.prototype.constructor.apply(this,[]);var l=a(b);if(!l.length)throw new Error("Could not find the trigger");this._scaleConfig=c,this._competencyId=d,this._userId=e,this._planId=g,this._courseId=h,this._chooseStr=i,this._canGrade=j,this._canSuggest=k,this._setUp(),l.click(function(a){a.preventDefault(),this._dialogue.display()}.bind(this)),this._planId?(this._methodName="tool_lp_grade_competency_in_plan",this._args={competencyid:this._competencyId,planid:this._planId}):this._courseId?(this._methodName="tool_lp_grade_competency_in_course",this._args={competencyid:this._competencyId,courseid:this._courseId,userid:this._userId}):(this._methodName="tool_lp_grade_competency",this._args={userid:this._userId,competencyid:this._competencyId})};return g.prototype=Object.create(f.prototype),g.prototype._setUp=function(){var a=[],d=this;a.push({value:"",name:this._chooseStr});for(var f=1;f. + +/** + * Grade dialogue. + * + * @package tool_lp + * @copyright 2016 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define(['jquery', + 'core/notification', + 'core/templates', + 'tool_lp/dialogue', + 'tool_lp/event_base', + 'core/str'], + function($, Notification, Templates, Dialogue, EventBase, Str) { + + /** + * Grade dialogue class. + */ + var Grade = function(ratingOptions, canGrade, canSuggest) { + EventBase.prototype.constructor.apply(this, []); + this._ratingOptions = ratingOptions; + this._canGrade = canGrade || false; + this._canSuggest = canSuggest || false; + }; + Grade.prototype = Object.create(EventBase.prototype); + + /** @type {Dialogue} The dialogue. */ + Grade.prototype._popup = null; + /** @type {Boolean} Can grade. */ + Grade.prototype._canGrade = false; + /** @type {Boolean} Can suggest. */ + Grade.prototype._canSuggest = false; + /** @type {Array} Array of objects containing, 'value', 'name' and optionally 'selected'. */ + Grade.prototype._ratingOptions = null; + + /** + * After render hook. + * + * @return {Promise} + * @method _afterRender + * @protected + */ + Grade.prototype._afterRender = function() { + var btnRate = this._find('[data-action="rate"]'), + btnSuggest = this._find('[data-action="suggest"]'), + lstRating = this._find('[name="rating"]'), + txtComment = this._find('[name="comment"]'); + + this._find('[data-action="cancel"]').click(function(e) { + e.preventDefault(); + this._trigger('cancelled'); + this.close(); + }.bind(this)); + + lstRating.change(function() { + var node = $(this); + if (!node.val()) { + btnRate.prop('disabled', true); + btnSuggest.prop('disabled', true); + } else { + btnRate.prop('disabled', false); + btnSuggest.prop('disabled', false); + } + }).change(); + + btnRate.click(function(e) { + e.preventDefault(); + var val = lstRating.val(); + if (!val) { + return; + } + this._trigger('rated', { + 'rating': val, + 'note': txtComment.val() + }); + this.close(); + }.bind(this)); + btnSuggest.click(function(e) { + e.preventDefault(); + var val = lstRating.val(); + if (!val) { + return; + } + this._trigger('suggested', { + 'rating': val, + 'note': txtComment.val() + }); + this.close(); + }.bind(this)); + }; + + /** + * Close the dialogue. + * + * @method close + */ + Grade.prototype.close = function() { + this._popup.close(); + this._popup = null; + }; + + /** + * Opens the picker. + * + * @param {Number} competencyId The competency ID of the competency to work on. + * @method display + * @return {Promise} + */ + Grade.prototype.display = function() { + return this._render().then(function(html) { + return Str.get_string('rate', 'tool_lp').then(function(title) { + this._popup = new Dialogue( + title, + html, + this._afterRender.bind(this) + ); + }.bind(this)); + }.bind(this)).fail(Notification.exception); + }; + + /** + * Find a node in the dialogue. + * + * @param {String} selector + * @method _find + * @protected + */ + Grade.prototype._find = function(selector) { + return $(this._popup.getContent()).find(selector); + }; + + /** + * Render the dialogue. + * + * @method _render + * @protected + * @return {Promise} + */ + Grade.prototype._render = function() { + var context = { + cangrade: this._canGrade, + cansuggest: this._canSuggest, + ratings: this._ratingOptions + }; + return Templates.render('tool_lp/competency_grader', context); + }; + + return /** @alias module:tool_lp/grade_dialogue */ Grade; + +}); diff --git a/admin/tool/lp/amd/src/grade_user_competency_inline.js b/admin/tool/lp/amd/src/grade_user_competency_inline.js index f392b08e086..968620c838e 100644 --- a/admin/tool/lp/amd/src/grade_user_competency_inline.js +++ b/admin/tool/lp/amd/src/grade_user_competency_inline.js @@ -21,30 +21,49 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define(['jquery', 'core/notification', 'core/ajax', 'core/log'], function($, notification, ajax, log) { +define(['jquery', + 'core/notification', + 'core/ajax', + 'core/log', + 'tool_lp/grade_dialogue', + 'tool_lp/event_base', + ], function($, notification, ajax, log, GradeDialogue, EventBase) { /** * InlineEditor * - * @param {String} The id of the form element. + * @param {String} selector The selector to trigger the grading. * @param {Object} The scale config for this competency. * @param {Number} The id of the competency. * @param {Number} The id of the user. * @param {Number} The id of the plan. * @param {Number} The id of the course. * @param {String} Language string for choose a rating. + * @param {Boolean} canGrade Whether the user can grade. + * @param {Boolean} canSuggest Whether the user can suggest. */ - var InlineEditor = function(formId, scaleConfig, competencyId, userId, planId, courseId, chooseStr) { - this._formId = formId; + var InlineEditor = function(selector, scaleConfig, competencyId, userId, planId, courseId, chooseStr, canGrade, canSuggest) { + EventBase.prototype.constructor.apply(this, []); + + var trigger = $(selector); + if (!trigger.length) { + throw new Error('Could not find the trigger'); + } + this._scaleConfig = scaleConfig; this._competencyId = competencyId; this._userId = userId; this._planId = planId; this._courseId = courseId; - this._valid = true; this._chooseStr = chooseStr; - this._buildSelect(); - this._addListeners(); + this._canGrade = canGrade; + this._canSuggest = canSuggest; + this._setUp(); + + trigger.click(function(e) { + e.preventDefault(); + this._dialogue.display(); + }.bind(this)); if (this._planId) { this._methodName = 'tool_lp_grade_competency_in_plan'; @@ -67,134 +86,61 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/log'], function($, not }; } }; + InlineEditor.prototype = Object.create(EventBase.prototype); /** - * Add all the options to the select. + * Setup. * - * @method _buildSelect + * @method _setUp */ - InlineEditor.prototype._buildSelect = function() { - var i = 1; + InlineEditor.prototype._setUp = function() { + var options = [], + self = this; - var blankOption = $(''); - blankOption.text(this._chooseStr); - blankOption.attr('value', ''); - $(document.getElementById(this._formId)).find('select').append(blankOption); - // The first item is the scaleid - we don't care about that. - for (i = 1; i < this._scaleConfig.length; i++) { + options.push({ + value: '', + name: this._chooseStr + }); + + for (var i = 1; i < this._scaleConfig.length; i++) { var optionConfig = this._scaleConfig[i]; - var optionEle = $(''); - optionEle.text(optionConfig.name); - optionEle.attr('value', optionConfig.id); - - $(document.getElementById(this._formId)).find('select').append(optionEle); + options.push({ + value: optionConfig.id, + name: optionConfig.name + }); } - }; - /** - * Handle grade button click - * - * @param {Event} event - * @method _handleGrade - */ - InlineEditor.prototype._handleGrade = function(event) { - var currentthis = this; - var grade = $(document.getElementById(this._formId)).find('select').val(); - event.preventDefault(); - if (this._valid && grade) { + this._dialogue = new GradeDialogue(options, this._canGrade, this._canSuggest); + this._dialogue.on('rated', function(e, data) { var args = this._args; - args.grade = grade; + args.grade = data.rating; + args.note = data.note; args.override = true; - ajax.call([{ methodname: this._methodName, args: args, done: function(evidence) { - currentthis._trigger('competencyupdated', { args: args, evidence: evidence}); - }, + this._trigger('competencyupdated', { args: args, evidence: evidence }); + }.bind(self), fail: notification.exception }]); - } - }; - - /** - * Handle suggest button click - * - * @param {Event} event - * @method _handleSuggest - */ - InlineEditor.prototype._handleSuggest = function(event) { - var currentthis = this; - var grade = $(document.getElementById(this._formId)).find('select').val(); - event.preventDefault(); - if (this._valid && grade) { + }.bind(this)); + this._dialogue.on('suggested', function(e, data) { var args = this._args; - args.grade = grade; + args.grade = data.rating; + args.note = data.note; args.override = false; ajax.call([{ methodname: this._methodName, args: args, done: function(evidence) { - currentthis._trigger('competencyupdated', { args: args, evidence: evidence}); - }, + this._trigger('competencyupdated', { args: args, evidence: evidence }); + }.bind(self), fail: notification.exception }]); - } + }.bind(this)); }; - /** - * Setup event listeners. - * - * @method _addListeners - */ - InlineEditor.prototype._addListeners = function() { - var currentthis = this; - var form = $(document.getElementById(this._formId)); - var gradebutton = form.find('[data-action="grade"]'); - gradebutton.on('click', function(event) { - currentthis._handleGrade.call(currentthis, event); - }); - var suggestbutton = form.find('[data-action="suggest"]'); - suggestbutton.on('click', function(event) { - currentthis._handleSuggest.call(currentthis, event); - }); - }; - - /** - * Trigger an event from this module. - * - * @param {String} eventname - Only 'competencyupdated' is supported - * @param {Object} arguments - Additional arguments for the event. - * @return InlineEditor for chaining - * @method _trigger - */ - InlineEditor.prototype._trigger = function(eventname, data) { - if (eventname != 'competencyupdated') { - notification.exception('Invalid event name:' + eventname); - } - $(document.getElementById(this._formId)).trigger(eventname, data); - return this; - }; - - /** - * Attach a listener for events triggered from this module. - * - * @param {String} eventname - Only 'competencyupdated' is supported - * @param {Function} handler - Event handler to call when this event is triggered. - * @return InlineEditor for chaining - * @method on - */ - InlineEditor.prototype.on = function(eventname, handler) { - if (eventname != 'competencyupdated') { - notification.exception('Invalid event name:' + eventname); - } - $(document.getElementById(this._formId)).on(eventname, handler); - return this; - }; - - - /** @type {String} The id of the select element. */ - InlineEditor.prototype._formId = null; /** @type {Object} The scale config for this competency. */ InlineEditor.prototype._scaleConfig = null; /** @type {Number} The id of the competency. */ @@ -205,8 +151,12 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/log'], function($, not InlineEditor.prototype._planId = null; /** @type {Number} The id of the course. */ InlineEditor.prototype._courseId = null; - /** @type {Boolean} Is this module valid. */ - InlineEditor.prototype._valid = null; + /** @type {GradeDialogue} The grading dialogue. */ + InlineEditor.prototype._dialogue = null; + /** @type {Boolean} Can grade. */ + InlineEditor.prototype._canGrade = null; + /** @type {Boolean} Can suggest. */ + InlineEditor.prototype._canSuggest = null; return /** @alias module:tool_lp/grade_user_competency_inline */ InlineEditor; diff --git a/admin/tool/lp/classes/api.php b/admin/tool/lp/classes/api.php index 7b56855377f..f6b656152c8 100644 --- a/admin/tool/lp/classes/api.php +++ b/admin/tool/lp/classes/api.php @@ -3731,6 +3731,7 @@ class api { * @param int $actionuserid The ID of the user who took the action of adding the evidence. Null when system. * This should be used when the action was taken by a real person, this will allow * to keep track of all the evidence given by a certain person. + * @param string $note A note to attach to the evidence. * @return evidence */ public static function add_evidence($userid, @@ -3743,7 +3744,8 @@ class api { $recommend = false, $url = null, $grade = null, - $actionuserid = null) { + $actionuserid = null, + $note = null) { global $DB; // Some clearly important variable assignments right there. @@ -3846,6 +3848,7 @@ class api { $record->desccomponent = $desccomponent; $record->grade = $grade; $record->actionuserid = $actionuserid; + $record->note = $note; $evidence = new evidence(0, $record); $evidence->set_desca($desca); $evidence->set_url($url); @@ -4075,9 +4078,10 @@ class api { * @param int $competencyid * @param int $grade * @param boolean $override + * @param string $note A note to attach to the evidence * @return array of \tool_lp\user_competency */ - public static function grade_competency($userid, $competencyid, $grade, $override) { + public static function grade_competency($userid, $competencyid, $grade, $override, $note = null) { global $USER; $uc = static::get_user_competency($userid, $competencyid); @@ -4116,7 +4120,8 @@ class api { false, null, $grade, - $USER->id); + $USER->id, + $note); } /** @@ -4126,9 +4131,10 @@ class api { * @param int $competencyid * @param int $grade * @param boolean $override + * @param string $note A note to attach to the evidence * @return array of \tool_lp\user_competency */ - public static function grade_competency_in_plan($planorid, $competencyid, $grade, $override) { + public static function grade_competency_in_plan($planorid, $competencyid, $grade, $override, $note = null) { global $USER; $plan = $planorid; @@ -4171,7 +4177,8 @@ class api { false, null, $grade, - $USER->id); + $USER->id, + $note); } /** @@ -4182,9 +4189,10 @@ class api { * @param int $competencyid * @param int $grade * @param boolean $override + * @param string $note A note to attach to the evidence * @return array of \tool_lp\user_competency */ - public static function grade_competency_in_course($courseorid, $userid, $competencyid, $grade, $override) { + public static function grade_competency_in_course($courseorid, $userid, $competencyid, $grade, $override, $note = null) { global $USER, $DB; $course = $courseorid; @@ -4226,7 +4234,8 @@ class api { false, null, $grade, - $USER->id); + $USER->id, + $note); } /** diff --git a/admin/tool/lp/classes/evidence.php b/admin/tool/lp/classes/evidence.php index 98554816f78..162ed618114 100644 --- a/admin/tool/lp/classes/evidence.php +++ b/admin/tool/lp/classes/evidence.php @@ -93,6 +93,11 @@ class evidence extends persistent { 'type' => PARAM_INT, 'default' => null, 'null' => NULL_ALLOWED + ), + 'note' => array( + 'type' => PARAM_NOTAGS, + 'default' => null, + 'null' => NULL_ALLOWED ) ); } diff --git a/admin/tool/lp/classes/external.php b/admin/tool/lp/classes/external.php index 6fb3eab6312..d6313d96900 100644 --- a/admin/tool/lp/classes/external.php +++ b/admin/tool/lp/classes/external.php @@ -4840,12 +4840,18 @@ class external extends external_api { 'Override the grade, or just suggest it', VALUE_REQUIRED ); + $note = new external_value( + PARAM_NOTAGS, + 'A note to attach to the evidence', + VALUE_DEFAULT + ); $params = array( 'userid' => $userid, 'competencyid' => $competencyid, 'grade' => $grade, - 'override' => $override + 'override' => $override, + 'note' => $note, ); return new external_function_parameters($params); } @@ -4857,15 +4863,17 @@ class external extends external_api { * @param int $competencyid The competency id * @param int $grade The new grade value * @param bool $override Override the grade or only suggest it + * @param string $note A note to attach to the evidence * @return bool */ - public static function grade_competency($userid, $competencyid, $grade, $override) { + public static function grade_competency($userid, $competencyid, $grade, $override, $note = null) { global $USER, $PAGE; $params = self::validate_parameters(self::grade_competency_parameters(), array( 'userid' => $userid, 'competencyid' => $competencyid, 'grade' => $grade, - 'override' => $override + 'override' => $override, + 'note' => $note )); $uc = api::get_user_competency($params['userid'], $params['competencyid']); @@ -4876,7 +4884,8 @@ class external extends external_api { $uc->get_userid(), $uc->get_competencyid(), $params['grade'], - $params['override'] + $params['override'], + $params['note'] ); $scale = $uc->get_competency()->get_scale(); @@ -4919,12 +4928,18 @@ class external extends external_api { 'Override the grade, or just suggest it', VALUE_REQUIRED ); + $note = new external_value( + PARAM_NOTAGS, + 'A note to attach to the evidence', + VALUE_DEFAULT + ); $params = array( 'planid' => $planid, 'competencyid' => $competencyid, 'grade' => $grade, - 'override' => $override + 'override' => $override, + 'note' => $note ); return new external_function_parameters($params); } @@ -4936,9 +4951,10 @@ class external extends external_api { * @param int $competencyid The competency id * @param int $grade The new grade value * @param bool $override Override the grade or only suggest it + * @param string $note A note to add to the evidence * @return bool */ - public static function grade_competency_in_plan($planid, $competencyid, $grade, $override) { + public static function grade_competency_in_plan($planid, $competencyid, $grade, $override, $note = null) { global $USER, $PAGE; $params = self::validate_parameters(self::grade_competency_in_plan_parameters(), @@ -4946,7 +4962,8 @@ class external extends external_api { 'planid' => $planid, 'competencyid' => $competencyid, 'grade' => $grade, - 'override' => $override + 'override' => $override, + 'note' => $note )); $plan = new plan($params['planid']); @@ -4958,7 +4975,8 @@ class external extends external_api { $plan->get_id(), $params['competencyid'], $params['grade'], - $params['override'] + $params['override'], + $params['note'] ); $competency = api::read_competency($params['competencyid']); $scale = $competency->get_scale(); @@ -5180,13 +5198,19 @@ class external extends external_api { 'Override the grade, or just suggest it', VALUE_REQUIRED ); + $note = new external_value( + PARAM_NOTAGS, + 'A note to attach to the evidence', + VALUE_DEFAULT + ); $params = array( 'courseid' => $courseid, 'userid' => $userid, 'competencyid' => $competencyid, 'grade' => $grade, - 'override' => $override + 'override' => $override, + 'note' => $note, ); return new external_function_parameters($params); } @@ -5199,9 +5223,10 @@ class external extends external_api { * @param int $competencyid The competency id * @param int $grade The new grade value * @param bool $override Override the grade or only suggest it + * @param string $note A note to add to the evidence * @return bool */ - public static function grade_competency_in_course($courseid, $userid, $competencyid, $grade, $override) { + public static function grade_competency_in_course($courseid, $userid, $competencyid, $grade, $override, $note = null) { global $USER, $PAGE, $DB; $params = self::validate_parameters(self::grade_competency_in_course_parameters(), @@ -5210,7 +5235,8 @@ class external extends external_api { 'userid' => $userid, 'competencyid' => $competencyid, 'grade' => $grade, - 'override' => $override + 'override' => $override, + 'note' => $note )); $course = $DB->get_record('course', array('id' => $params['courseid'])); @@ -5223,7 +5249,8 @@ class external extends external_api { $params['userid'], $params['competencyid'], $params['grade'], - $params['override'] + $params['override'], + $params['note'] ); $competency = api::read_competency($params['competencyid']); $scale = $competency->get_scale(); diff --git a/admin/tool/lp/db/install.xml b/admin/tool/lp/db/install.xml index 98fca2b0244..d9e8ed48596 100755 --- a/admin/tool/lp/db/install.xml +++ b/admin/tool/lp/db/install.xml @@ -1,5 +1,5 @@ - @@ -231,6 +231,7 @@ + diff --git a/admin/tool/lp/db/upgrade.php b/admin/tool/lp/db/upgrade.php index f54595a1d2f..edc560e1295 100644 --- a/admin/tool/lp/db/upgrade.php +++ b/admin/tool/lp/db/upgrade.php @@ -698,5 +698,20 @@ function xmldb_tool_lp_upgrade($oldversion) { upgrade_plugin_savepoint(true, 2015111041, 'tool', 'lp'); } + if ($oldversion < 2016020900) { + + // Define field note to be added to tool_lp_evidence. + $table = new xmldb_table('tool_lp_evidence'); + $field = new xmldb_field('note', XMLDB_TYPE_TEXT, null, null, null, null, null, 'grade'); + + // Conditionally launch add field note. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Lp savepoint reached. + upgrade_plugin_savepoint(true, 2016020900, '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 7b3f348c6ae..419e1adf40b 100644 --- a/admin/tool/lp/lang/en/tool_lp.php +++ b/admin/tool/lp/lang/en/tool_lp.php @@ -242,6 +242,7 @@ $string['pointsgivenfor'] = 'Points given for \'{$a}\''; $string['pointsrequiredaremet'] = 'Points required are met'; $string['proficient'] = 'Proficient'; $string['rate'] = 'Rate'; +$string['ratecomment'] = 'Evidence notes'; $string['rating'] = 'Rating'; $string['relatedcompetencies'] = 'Related competencies'; $string['reviewstatus'] = 'Review status'; diff --git a/admin/tool/lp/styles.css b/admin/tool/lp/styles.css index 4e25f48f174..6e6f6ebde38 100644 --- a/admin/tool/lp/styles.css +++ b/admin/tool/lp/styles.css @@ -203,3 +203,10 @@ input[type="checkbox"].tool_lp_scale_proficient { .user-competency-course-navigation { width: 240px; } + +/** Competency grader */ +.competency-grader textarea { + width: 100%; + max-width: 100%; + box-sizing: border-box; +} diff --git a/admin/tool/lp/templates/competency_grader.mustache b/admin/tool/lp/templates/competency_grader.mustache new file mode 100644 index 00000000000..0572f300e50 --- /dev/null +++ b/admin/tool/lp/templates/competency_grader.mustache @@ -0,0 +1,31 @@ +
+
+
+
+ + +
+
+ + +
+
+
+
+ {{#cansuggest}} + + {{/cansuggest}} + {{#cangrade}} + + {{/cangrade}} +
+
+ +
+
+
+
diff --git a/admin/tool/lp/templates/evidence_summary.mustache b/admin/tool/lp/templates/evidence_summary.mustache index 7d0a1e0a519..d81b8389731 100644 --- a/admin/tool/lp/templates/evidence_summary.mustache +++ b/admin/tool/lp/templates/evidence_summary.mustache @@ -53,6 +53,9 @@

{{gradename}}

{{/grade}}

{{description}}

+{{#note}} +
{{note}}
+{{/note}} {{#url}}

{{url}}

{{/url}} diff --git a/admin/tool/lp/templates/user_competency_summary.mustache b/admin/tool/lp/templates/user_competency_summary.mustache index 62b48200f0f..248f71afdf7 100644 --- a/admin/tool/lp/templates/user_competency_summary.mustache +++ b/admin/tool/lp/templates/user_competency_summary.mustache @@ -38,7 +38,7 @@ This template does not have an example context because it includes ajax functionality. }} -
+
{{#competency}} {{> tool_lp/competency_summary }} @@ -65,28 +65,15 @@
{{#str}}rating, tool_lp{{/str}}
{{gradename}} -

-

{{#cangradeorsuggest}} - -
- {{#cangrade}} - - {{/cangrade}} - {{#cansuggest}} - - {{/cansuggest}} -
-

+ {{#str}}rate, tool_lp{{/str}} {{/cangradeorsuggest}} - -

{{#js}} require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info', 'tool_lp/user_competency_workflow'], function($, mod, info, UserCompWorkflow) { var scaleConfig = JSON.parse('{{{competency.scaleconfiguration}}}'); - var competencyElement = $(document.getElementById('grade-competency-form-{{uniqid}}')).closest('[data-region=user-competency-full-info]'); + var competencyElement = $('[data-region-id="{{uniqid}}"]'); var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}'); var ucw = new UserCompWorkflow(); @@ -94,7 +81,7 @@ ucw.on('status-changed', infoReloader.reload.bind(infoReloader)); ucw.on('error-occured', infoReloader.reload.bind(infoReloader)); - var inlineGrader = new mod('grade-competency-form-{{uniqid}}', scaleConfig, '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}'); + var inlineGrader = new mod('#rate_{{uniqid}}', scaleConfig, '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}', {{cangrade}}, {{cansuggest}}); inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader)); }); {{/js}} diff --git a/admin/tool/lp/templates/user_competency_summary_in_course.mustache b/admin/tool/lp/templates/user_competency_summary_in_course.mustache index 4e98dbe01bf..638df241c33 100644 --- a/admin/tool/lp/templates/user_competency_summary_in_course.mustache +++ b/admin/tool/lp/templates/user_competency_summary_in_course.mustache @@ -73,29 +73,15 @@
{{#str}}rating, tool_lp{{/str}}
{{gradename}} - {{#cangradeorsuggest}} -

-

- -
- {{#cangrade}} - - {{/cangrade}} - {{#cansuggest}} - - {{/cansuggest}} -
- -
-

-

- {{/cangradeorsuggest}} + {{#cangradeorsuggest}} + {{#str}}rate, tool_lp{{/str}} + {{/cangradeorsuggest}}
{{#js}} require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info'], function($, mod, info) { var scaleConfig = JSON.parse('{{{competency.scaleconfiguration}}}'); - var inlineGrader = new mod('grade-competency-form-{{uniqid}}', scaleConfig, '{{competency.competency.id}}', '{{user.id}}', '', '{{course.id}}', '{{#str}}chooserating, tool_lp{{/str}}'); + var inlineGrader = new mod('#rate_{{uniqid}}', scaleConfig, '{{competency.competency.id}}', '{{user.id}}', '', '{{course.id}}', '{{#str}}chooserating, tool_lp{{/str}}', {{cangrade}}, {{cansuggest}}); var competencyElement = $('[data-region-id="{{uniqid}}"]'); var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}', '', '{{course.id}}'); diff --git a/admin/tool/lp/templates/user_competency_summary_in_plan.mustache b/admin/tool/lp/templates/user_competency_summary_in_plan.mustache index d61dd1ba329..d93ed0bd172 100644 --- a/admin/tool/lp/templates/user_competency_summary_in_plan.mustache +++ b/admin/tool/lp/templates/user_competency_summary_in_plan.mustache @@ -40,7 +40,7 @@ This template does not have an example context because it includes ajax functionality. }} {{#usercompetencysummary}} -
+
{{#competency}} {{> tool_lp/competency_summary }} @@ -67,28 +67,15 @@
{{#str}}rating, tool_lp{{/str}}
{{gradename}} -

-

{{#cangradeorsuggest}} - -
- {{#cangrade}} - - {{/cangrade}} - {{#cansuggest}} - - {{/cansuggest}} -
-

+ {{#str}}rate, tool_lp{{/str}} {{/cangradeorsuggest}} - -

{{#js}} require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info', 'tool_lp/user_competency_workflow'], function($, mod, info, UserCompWorkflow) { var scaleConfig = JSON.parse('{{{competency.scaleconfiguration}}}'); - var competencyElement = $(document.getElementById('grade-competency-form-{{uniqid}}')).closest('[data-region=user-competency-full-info]'); + var competencyElement = $('[data-region-id="{{uniqid}}"]'); var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}'); var ucw = new UserCompWorkflow(); @@ -96,19 +83,16 @@ ucw.on('status-changed', infoReloader.reload.bind(infoReloader)); ucw.on('error-occured', infoReloader.reload.bind(infoReloader)); - var inlineGrader = new mod('grade-competency-form-{{uniqid}}', scaleConfig, '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}'); - inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader)); + {{#cangradeorsuggest}} + var inlineGrader = new mod('#rate_{{uniqid}}', scaleConfig, '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}', {{cangrade}}, {{cansuggest}}); + inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader)); + {{/cangradeorsuggest}} }); {{/js}} {{/usercompetency}} {{#usercompetencyplan}}
{{#str}}rating, tool_lp{{/str}}
{{gradename}} - {{#str}}plancompleted, tool_lp{{/str}}
- {{#cangradeorsuggest}} - {{$gradeform}} - - {{/gradeform}} - {{/cangradeorsuggest}}
{{#str}}proficient, tool_lp{{/str}}
diff --git a/admin/tool/lp/tests/api_test.php b/admin/tool/lp/tests/api_test.php index cb29d4893ea..7f57fb37309 100644 --- a/admin/tool/lp/tests/api_test.php +++ b/admin/tool/lp/tests/api_test.php @@ -1759,7 +1759,7 @@ class tool_lp_api_testcase extends advanced_testcase { // Creating a standard evidence with more information. $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \tool_lp\evidence::ACTION_LOG, 'invaliddata', 'error', - '$a', false, 'http://moodle.org', null, 2); + '$a', false, 'http://moodle.org', null, 2, 'The evidence of prior learning were reviewed.'); $evidence->read(); $uc = \tool_lp\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id())); $this->assertEquals(\tool_lp\user_competency::STATUS_IDLE, $uc->get_status()); @@ -1774,6 +1774,7 @@ class tool_lp_api_testcase extends advanced_testcase { $this->assertEquals('http://moodle.org', $evidence->get_url()); $this->assertSame(null, $evidence->get_grade()); $this->assertEquals(2, $evidence->get_actionuserid()); + $this->assertSame('The evidence of prior learning were reviewed.', $evidence->get_note()); // Creating a standard evidence and send for review. $evidence = api::add_evidence($u1->id, $c2->get_id(), $u1ctx->id, \tool_lp\evidence::ACTION_LOG, 'invaliddata', diff --git a/admin/tool/lp/tests/externallib_test.php b/admin/tool/lp/tests/externallib_test.php index e1b67f330b9..26f6ddb0250 100644 --- a/admin/tool/lp/tests/externallib_test.php +++ b/admin/tool/lp/tests/externallib_test.php @@ -2860,10 +2860,11 @@ class tool_lp_external_testcase extends externallib_advanced_testcase { $uc = $lpg->create_user_competency(array('userid' => $this->user->id, 'competencyid' => $c1->get_id())); - $evidence = external::grade_competency_in_plan($plan->get_id(), $c1->get_id(), 1, false); + $evidence = external::grade_competency_in_plan($plan->get_id(), $c1->get_id(), 1, false, 'Evil note'); $this->assertEquals('The competency grade was manually suggested in the plan \'Evil\'.', $evidence->description); $this->assertEquals('A', $evidence->gradename); + $this->assertEquals('Evil note', $evidence->note); $evidence = external::grade_competency_in_plan($plan->get_id(), $c1->get_id(), 1, true); $this->assertEquals('The competency grade was manually set in the plan \'Evil\'.', $evidence->description); diff --git a/admin/tool/lp/version.php b/admin/tool/lp/version.php index 2fc382c3807..4067d4efe32 100644 --- a/admin/tool/lp/version.php +++ b/admin/tool/lp/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2015111051; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2016020900; // 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).