From 5f887f4b9690405c4a2a2fee49e001e68ac4c777 Mon Sep 17 00:00:00 2001 From: Issam Taboubi Date: Fri, 1 Apr 2016 16:59:43 -0400 Subject: [PATCH] MDL-53528 tool_lp: Allow user to choose parent when creating competency --- .../build/course_competency_settings.min.js | 2 +- .../lp/amd/build/parentcompetency_form.min.js | 1 + .../tool/lp/amd/src/parentcompetency_form.js | 207 ++++++++++++++++++ admin/tool/lp/classes/form/competency.php | 42 +++- admin/tool/lp/editcompetency.php | 3 +- admin/tool/lp/lang/en/tool_lp.php | 5 +- .../competency_picker_competencyform.mustache | 22 ++ admin/tool/lp/version.php | 2 +- 8 files changed, 270 insertions(+), 14 deletions(-) create mode 100644 admin/tool/lp/amd/build/parentcompetency_form.min.js create mode 100644 admin/tool/lp/amd/src/parentcompetency_form.js create mode 100644 admin/tool/lp/templates/competency_picker_competencyform.mustache diff --git a/admin/tool/lp/amd/build/course_competency_settings.min.js b/admin/tool/lp/amd/build/course_competency_settings.min.js index 5fe246e85db02..1b1b54055d363 100644 --- a/admin/tool/lp/amd/build/course_competency_settings.min.js +++ b/admin/tool/lp/amd/build/course_competency_settings.min.js @@ -1 +1 @@ -define(["jquery","core/notification","tool_lp/dialogue","core/str","core/ajax","core/templates"],function(a,b,c,d,e,f){var g=function(b){a(b).on("click",this.configureSettings.bind(this))};return g.prototype._dialogue=null,g.prototype.configureSettings=function(e){var g=a(e.target).closest("a").data("courseid"),h=a(e.target).closest("a").data("pushratingstouserplans"),i={courseid:g,settings:{pushratingstouserplans:h}};e.preventDefault(),f.render("tool_lp/course_competency_settings",i).done(function(a){d.get_string("configurecoursecompetencysettings","tool_lp").done(function(b){this._dialogue=new c(b,a,this.addListeners.bind(this))}.bind(this)).fail(b.exception)}.bind(this)).fail(b.exception)},g.prototype.addListeners=function(){var a=this._find('[data-action="save"]');a.on("click",this.saveSettings.bind(this));var b=this._find('[data-action="cancel"]');b.on("click",this.cancelChanges.bind(this))},g.prototype.cancelChanges=function(a){a.preventDefault(),this._dialogue.close()},g.prototype._find=function(b){return a('[data-region="coursecompetencysettings"]').find(b)},g.prototype.saveSettings=function(a){a.preventDefault();var c=this._find('input[name="pushratingstouserplans"]:checked').val(),d=this._find('input[name="courseid"]').val(),f={pushratingstouserplans:c};e.call([{methodname:"core_competency_update_course_competency_settings",args:{courseid:d,settings:f}}])[0].done(function(){this.refreshCourseCompetenciesPage()}.bind(this)).fail(b.exception)},g.prototype.refreshCourseCompetenciesPage=function(){var c=this._find('input[name="courseid"]').val();e.call([{methodname:"tool_lp_data_for_course_competencies_page",args:{courseid:c}}])[0].done(function(c){f.render("tool_lp/course_competencies_page",c).done(function(b,c){a('[data-region="coursecompetenciespage"]').replaceWith(b),f.runTemplateJS(c),this._dialogue.close()}.bind(this)).fail(b.exception)}.bind(this)).fail(b.exception)},g}); \ No newline at end of file +define(["jquery","core/notification","tool_lp/dialogue","core/str","core/ajax","core/templates"],function(a,b,c,d,e,f){var g=function(b){a(b).on("click",this.configureSettings.bind(this))};return g.prototype._dialogue=null,g.prototype.configureSettings=function(e){var g=a(e.target).closest("a").data("courseid"),h=a(e.target).closest("a").data("pushratingstouserplans"),i={courseid:g,settings:{pushratingstouserplans:h}};e.preventDefault(),f.render("tool_lp/course_competency_settings",i).done(function(a){d.get_string("configurecoursecompetencysettings","tool_lp").done(function(b){this._dialogue=new c(b,a,this.addListeners.bind(this))}.bind(this)).fail(b.exception)}.bind(this)).fail(b.exception)},g.prototype.addListeners=function(){var a=this._find('[data-action="save"]');a.on("click",this.saveSettings.bind(this));var b=this._find('[data-action="cancel"]');b.on("click",this.cancelChanges.bind(this))},g.prototype.cancelChanges=function(a){a.preventDefault(),this._dialogue.close()},g.prototype._find=function(b){return a('[data-region="coursecompetencysettings"]').find(b)},g.prototype.saveSettings=function(a){a.preventDefault();var c=this._find('input[name="pushratingstouserplans"]:checked').val(),d=this._find('input[name="courseid"]').val(),f={pushratingstouserplans:c};e.call([{methodname:"core_competency_update_course_competency_settings",args:{courseid:d,settings:f}}])[0].done(function(){this.refreshCourseCompetenciesPage()}.bind(this)).fail(b.exception)},g.prototype.refreshCourseCompetenciesPage=function(){var c=this._find('input[name="courseid"]').val();e.call([{methodname:"tool_lp_data_for_course_competencies_page",args:{courseid:c}}])[0].done(function(c){f.render("tool_lp/course_competencies_page",c).done(function(b,c){a('[data-region="coursecompetenciespage"]').replaceWith(b),f.runTemplateJS(c),this._dialogue.close()}.bind(this)).fail(b.exception)}.bind(this)).fail(b.exception)},g}); diff --git a/admin/tool/lp/amd/build/parentcompetency_form.min.js b/admin/tool/lp/amd/build/parentcompetency_form.min.js new file mode 100644 index 0000000000000..0161053629645 --- /dev/null +++ b/admin/tool/lp/amd/build/parentcompetency_form.min.js @@ -0,0 +1 @@ +define(["jquery","core/ajax","core/str","tool_lp/competencypicker","core/templates","core/notification"],function(a,b,c,d,e,f){var g=function(a,b,c,d,e,f){this.buttonSelector=a,this.inputHiddenSelector=b,this.staticElementSelector=c,this.frameworkId=d,this.frameworkMaxLevel=e,this.pageContextId=f,this.registerEvents()};return g.prototype.buttonSelector=null,g.prototype.inputHiddenSelector=null,g.prototype.staticElementSelector=null,g.prototype.frameworkId=null,g.prototype.frameworkMaxLevel=null,g.prototype.pageContextId=null,g.prototype.setParent=function(d){var e=this;0!==d.competencyId?b.call([{methodname:"core_competency_read_competency",args:{id:d.competencyId}}])[0].done(function(b){a(e.staticElementSelector).html(b.shortname),a(e.inputHiddenSelector).val(b.id)}).fail(f.exception):c.get_string("competencyframeworkroot","tool_lp").then(function(b){a(e.staticElementSelector).html(b),a(e.inputHiddenSelector).val(d.competencyId)}).fail(f.exception)},g.prototype.registerEvents=function(){var c=this;a(c.buttonSelector).on("click",function(a){a.preventDefault();var g=new d(c.pageContextId,c.frameworkId,"self",!1),h=c.frameworkMaxLevel;g._fetchCompetencies=function(a,c){var d=this;return b.call([{methodname:"core_competency_search_competencies",args:{searchtext:c,competencyframeworkid:a}}])[0].done(function(a){function b(a,c){for(var d=0;d=h&&"0"!==c[d].id&&f.push(c[d].id),c[d].parentid==a.id&&(a.haschildren=!0,c[d].children=[],c[d].haschildren=!1,a.children[a.children.length]=c[d],b(c[d],c))}}var c,e,f=[],g=[];for(c=0;c. + +/** + * Handle selecting parent competency in competency form. + * + * @module tool_lp/parentcompetency_form + * @package tool_lp + * @copyright 2015 Issam Taboubi + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery', 'core/ajax', 'core/str', 'tool_lp/competencypicker', 'core/templates', 'core/notification'], + function($, ajax, Str, Picker, Templates, Notification) { + + /** + * Parent Competency Form object. + * @param {String} buttonSelector The parent competency button selector. + * @param {String} inputHiddenSelector The hidden input field selector. + * @param {String} staticElementSelector The static element displaying the parent competency. + * @param {Number} frameworkId The competency framework ID. + * @param {Number} frameworkMaxLevel The framework max level. + * @param {Number} pageContextId The page context ID. + */ + var ParentCompetencyForm = function(buttonSelector, + inputHiddenSelector, + staticElementSelector, + frameworkId, + frameworkMaxLevel, + pageContextId) { + this.buttonSelector = buttonSelector; + this.inputHiddenSelector = inputHiddenSelector; + this.staticElementSelector = staticElementSelector; + this.frameworkId = frameworkId; + this.frameworkMaxLevel = frameworkMaxLevel; + this.pageContextId = pageContextId; + + // Register the events. + this.registerEvents(); + }; + + /** @var {String} The parent competency button selector. */ + ParentCompetencyForm.prototype.buttonSelector = null; + /** @var {String} The hidden input field selector. */ + ParentCompetencyForm.prototype.inputHiddenSelector = null; + /** @var {String} The static element displaying the parent competency. */ + ParentCompetencyForm.prototype.staticElementSelector = null; + /** @var {Number} The competency framework ID. */ + ParentCompetencyForm.prototype.frameworkId = null; + /** @var {Number} The framework max level. */ + ParentCompetencyForm.prototype.frameworkMaxLevel = null; + /** @var {Number} The page context ID. */ + ParentCompetencyForm.prototype.pageContextId = null; + + /** + * Set the parent competency in the competency form. + * + * @param {Object} Data containing selected cmpetency. + * @method setParent + */ + ParentCompetencyForm.prototype.setParent = function(data) { + var self = this; + + if (data.competencyId !== 0) { + ajax.call([ + { methodname: 'core_competency_read_competency', args: { + id: data.competencyId + }} + ])[0].done(function(competency) { + $(self.staticElementSelector).html(competency.shortname); + $(self.inputHiddenSelector).val(competency.id); + }).fail(Notification.exception); + } else { + // Root of competency framework selected. + Str.get_string('competencyframeworkroot', 'tool_lp').then(function(rootframework) { + $(self.staticElementSelector).html(rootframework); + $(self.inputHiddenSelector).val(data.competencyId); + }).fail(Notification.exception); + } + }; + + /** + * Register the events of parent competency button click. + * + * @method registerEvents + */ + ParentCompetencyForm.prototype.registerEvents = function() { + var self = this; + + // Event on edit parent button. + $(self.buttonSelector).on('click', function(e) { + e.preventDefault(); + + var picker = new Picker(self.pageContextId, self.frameworkId, 'self', false); + var maxlevel = self.frameworkMaxLevel; + // Override the fetchcompetencies method to filter by max level. + picker._fetchCompetencies = function(frameworkId, searchText) { + var self = this; + + return ajax.call([ + { methodname: 'core_competency_search_competencies', args: { + searchtext: searchText, + competencyframeworkid: frameworkId + }} + ])[0].done(function(competencies) { + + var disabledcompetencies = []; + function addCompetencyChildren(parent, competencies) { + for (var i = 0; i < competencies.length; i++) { + // Check if competency does not exceed the framework max level. + var path = String(competencies[i].path), + level = path.split('/').length - 2; + if (level >= maxlevel && competencies[i].id !== "0") { + disabledcompetencies.push(competencies[i].id); + } + + if (competencies[i].parentid == parent.id) { + parent.haschildren = true; + competencies[i].children = []; + competencies[i].haschildren = false; + parent.children[parent.children.length] = competencies[i]; + addCompetencyChildren(competencies[i], competencies); + } + } + } + + // Expand the list of competencies into a tree. + var i, tree = [], comp; + for (i = 0; i < competencies.length; i++) { + comp = competencies[i]; + if (comp.parentid == "0") { // Loose check for now, because WS returns a string. + comp.children = []; + comp.haschildren = 0; + tree[tree.length] = comp; + addCompetencyChildren(comp, competencies); + } + } + + self._competencies = tree; + self.setDisallowedCompetencyIDs(disabledcompetencies); + + }.bind(self)).fail(Notification.exception); + }; + // Override the render method to make framework selectable. + picker._render = function() { + var self = this; + return self._preRender().then(function() { + var context = { + competencies: self._competencies, + framework: self._getFramework(self._frameworkId), + frameworks: self._frameworks, + search: self._searchText, + singleFramework: self._singleFramework, + }; + + return Templates.render('tool_lp/competency_picker_competencyform', context); + }.bind(self)); + }; + + // On selected competency. + picker.on('save', function(e, data) { + self.setParent(data); + }.bind(self)); + + picker.display(); + }); + }; + + return { + + /** + * Main initialisation. + * @param {String} buttonSelector The parent competency button selector. + * @param {String} inputHiddenSelector The hidden input field selector. + * @param {String} staticElementSelector The static element displaying the parent competency. + * @param {Number} frameworkId The competency framework ID. + * @param {Number} frameworkMaxLevel The framework max level. + * @param {Number} pageContextId The page context ID. + * @method init + */ + init: function(buttonSelector, + inputSelector, + staticElementSelector, + frameworkId, + frameworkMaxLevel, + pageContextId) { + // Create instance. + new ParentCompetencyForm(buttonSelector, + inputSelector, + staticElementSelector, + frameworkId, + frameworkMaxLevel, + pageContextId); + } + }; +}); diff --git a/admin/tool/lp/classes/form/competency.php b/admin/tool/lp/classes/form/competency.php index da943c82d1920..b4bea6c353edc 100644 --- a/admin/tool/lp/classes/form/competency.php +++ b/admin/tool/lp/classes/form/competency.php @@ -36,17 +36,19 @@ */ class competency extends persistent { + /** @var core_competency\competency persistent class for form */ protected static $persistentclass = 'core_competency\\competency'; /** * Define the form - called by parent constructor */ public function definition() { - global $PAGE; + global $PAGE, $OUTPUT; $mform = $this->_form; $framework = $this->_customdata['competencyframework']; $parent = $this->_customdata['parent']; + $pagecontextid = $this->_customdata['pagecontextid']; $competency = $this->get_persistent(); $mform->addElement('hidden', 'competencyframeworkid'); @@ -59,15 +61,35 @@ public function definition() { 'frameworkdesc', get_string('competencyframework', 'tool_lp'), s($framework->get_shortname())); - if ($parent) { - $mform->addElement('hidden', 'parentid'); - $mform->setType('parentid', PARAM_INT); - $mform->setConstant('parentid', $parent->get_id()); - - $mform->addElement('static', - 'parentdesc', - get_string('taxonomy_parent_' . $framework->get_taxonomy($parent->get_level()), 'tool_lp'), - s($parent->get_shortname())); + + $mform->addElement('hidden', 'parentid', '', array('id' => 'tool_lp_parentcompetency')); + + $mform->setType('parentid', PARAM_INT); + $mform->setConstant('parentid', ($parent) ? $parent->get_id() : 0); + $parentlevel = ($parent) ? $parent->get_level() : 0; + $parentname = ($parent) ? $parent->get_shortname() : get_string('competencyframeworkroot', 'tool_lp'); + $parentlabel = ($competency->get_id()) ? + get_string('taxonomy_parent_' . $framework->get_taxonomy($parentlevel), 'tool_lp') : + get_string('parentcompetency', 'tool_lp'); + $editaction = ''; + if (!$competency->get_id()) { + $icon = $OUTPUT->pix_icon('t/editstring', get_string('parentcompetency_edit', 'tool_lp')); + $editaction = $OUTPUT->action_link('#', $icon, null, array('id' => 'id_parentcompetencybutton')); + } + + $mform->addElement('static', + 'parentdesc', + $parentlabel, + "$parentname ".$editaction); + // Set the picker competency when adding new competency. + if (!$competency->get_id()) { + // Call the parentcompetency_form init to initialize the competency picker for parent competency. + $PAGE->requires->js_call_amd('tool_lp/parentcompetency_form', 'init', array('#id_parentcompetencybutton', + '#tool_lp_parentcompetency', + '#id_parentdesc', + $framework->get_id(), + \core_competency\competency_framework::get_taxonomies_max_level(), + $pagecontextid)); } $mform->addElement('text', 'shortname', diff --git a/admin/tool/lp/editcompetency.php b/admin/tool/lp/editcompetency.php index 0cde79489be87..cbaa76e4f9912 100644 --- a/admin/tool/lp/editcompetency.php +++ b/admin/tool/lp/editcompetency.php @@ -77,7 +77,8 @@ $formoptions = [ 'competencyframework' => $competencyframework, 'parent' => $parent, - 'persistent' => $competency + 'persistent' => $competency, + 'pagecontextid' => $pagecontextid ]; $form = new \tool_lp\form\competency($url->out(false), $formoptions); diff --git a/admin/tool/lp/lang/en/tool_lp.php b/admin/tool/lp/lang/en/tool_lp.php index 801191f9f3ffc..65634be688378 100644 --- a/admin/tool/lp/lang/en/tool_lp.php +++ b/admin/tool/lp/lang/en/tool_lp.php @@ -58,6 +58,7 @@ $string['competencyframework'] = 'Competency framework'; $string['competencyframeworkcreated'] = 'Competency framework created.'; $string['competencyframeworkname'] = 'Name'; +$string['competencyframeworkroot'] = 'No parent (Top level competency)'; $string['competencyframeworks'] = 'Competency Frameworks'; $string['competencyframeworkupdated'] = 'Competency framework updated.'; $string['competencyoutcome_complete'] = 'Mark as complete'; @@ -156,8 +157,10 @@ $string['nouserplans'] = 'No learning plans have been created yet.'; $string['oneplanwascreated'] = 'A plan was created'; $string['outcome'] = 'Outcome'; -$string['parentcompetency'] = 'Parent competency'; $string['path'] = 'Path:'; +$string['parentcompetency'] = 'Parent'; +$string['parentcompetency_edit'] = 'Edit parent'; +$string['parentcompetency_help'] = 'Define the parent under which the competency will be added. It can either be another competency within the same framework, or the root of the competency framework for a top level competency.'; $string['planapprove'] = 'Make active'; $string['plancompleted'] = 'Plan completed'; $string['plancreated'] = 'Learning plan created'; diff --git a/admin/tool/lp/templates/competency_picker_competencyform.mustache b/admin/tool/lp/templates/competency_picker_competencyform.mustache new file mode 100644 index 0000000000000..f3f1ca04c461c --- /dev/null +++ b/admin/tool/lp/templates/competency_picker_competencyform.mustache @@ -0,0 +1,22 @@ +
+

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

+ +
+ + + +
+
    +
  • {{framework.shortname}} +
      + {{#competencies}} + {{> tool_lp/competencies_tree }} + {{/competencies}} +
    +
  • +
+
+ + +
+
diff --git a/admin/tool/lp/version.php b/admin/tool/lp/version.php index 350069424da21..b0351dcd71f8e 100644 --- a/admin/tool/lp/version.php +++ b/admin/tool/lp/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2016020924; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2016020925; // 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).