// 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 <http://www.gnu.org/licenses/>.
/**
* Handle selection changes on the competency tree.
*
* @module tool_lp/competencytree
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['core/ajax', 'core/notification', 'core/templates', 'tool_lp/tree', 'tool_lp/competency_outcomes', 'jquery'],
function(ajax, notification, templates, Ariatree, CompOutcomes, $) {
// Private variables and functions.
/** @var {Object[]} competencies - Cached list of competencies */
var competencies = {};
/** @var {Number} competencyFrameworkId - The current framework id */
var competencyFrameworkId = 0;
/** @var {String} competencyFrameworkShortName - The current framework short name */
var competencyFrameworkShortName = '';
/** @var {String} treeSelector - The selector for the root of the tree. */
var treeSelector = '';
/** @var {String} currentNodeId - The data-id of the current node in the tree. */
var currentNodeId = '';
/** @var {Boolean} competencyFramworkCanManage - Can manage the competencies framework */
var competencyFramworkCanManage = false;
/**
* Build a tree from the flat list of competencies.
* @param {Object} parent The parent competency.
* @param {Array} all The list of all competencies.
*/
var addChildren = function(parent, all) {
var i = 0;
var current = false;
parent.haschildren = false;
parent.children = [];
for (i = 0; i < all.length; i++) {
current = all[i];
if (current.parentid == parent.id) {
parent.haschildren = true;
parent.children.push(current);
addChildren(current, all);
}
}
};
/**
* Load the list of competencies via ajax. Competencies are filtered by the searchtext.
* @param {String} searchtext The text to filter on.
* @return {promise}
*/
var loadCompetencies = function(searchtext) {
var deferred = $.Deferred();
templates.render('tool_lp/loading', {}).done(function(loadinghtml, loadingjs) {
templates.replaceNodeContents($(treeSelector), loadinghtml, loadingjs);
var promises = ajax.call([{
methodname: 'core_competency_search_competencies',
args: {
searchtext: searchtext,
competencyframeworkid: competencyFrameworkId
}
}]);
promises[0].done(function(result) {
competencies = {};
var i = 0;
for (i = 0; i < result.length; i++) {
competencies[result[i].id] = result[i];
}
var children = [];
var competency = false;
for (i = 0; i < result.length; i++) {
competency = result[i];
if (parseInt(competency.parentid, 10) === 0) {
children.push(competency);
addChildren(competency, result);
}
}
var context = {
shortname: competencyFrameworkShortName,
canmanage: competencyFramworkCanManage,
competencies: children
};
templates.render('tool_lp/competencies_tree_root', context).done(function(html, js) {
templates.replaceNodeContents($(treeSelector), $(html).html(), js);
var tree = new Ariatree(treeSelector, false);
if (currentNodeId) {
var node = $(treeSelector).find('[data-id=' + currentNodeId + ']');
if (node.length) {
tree.selectItem(node);
tree.updateFocus(node);
}
}
deferred.resolve(competencies);
}).fail(deferred.reject);
}).fail(deferred.reject);
});
return deferred.promise();
};
/**
* Whenever the current item in the tree is changed - remember the "id".
* @param {Event} evt
* @param {Object} params The parameters for the event (This is the selected node).
*/
var rememberCurrent = function(evt, params) {
var node = params.selected;
currentNodeId = node.attr('data-id');
};
return /** @alias module:tool_lp/competencytree */ {
// Public variables and functions.
/**
* Initialise the tree.
*
* @param {Number} id The competency framework id.
* @param {String} shortname The framework shortname
* @param {String} search The current search string
* @param {String} selector The selector for the tree div
* @param {Boolean} canmanage Can manage the competencies
* @param {Number} competencyid The id of the competency to show first
*/
init: function(id, shortname, search, selector, canmanage, competencyid) {
competencyFrameworkId = id;
competencyFrameworkShortName = shortname;
competencyFramworkCanManage = canmanage;
treeSelector = selector;
loadCompetencies(search).fail(notification.exception);
if (competencyid > 0) {
currentNodeId = competencyid;
}
this.on('selectionchanged', rememberCurrent);
},
/**
* Add an event handler for custom events emitted by the tree.
*
* @param {String} eventname The name of the event - only "selectionchanged" for now
* @param {Function} handler The handler for the event.
*/
on: function(eventname, handler) {
// We can't use the tree on function directly
// because the tree gets rebuilt whenever the search string changes,
// instead we attach the listner to the root node of the tree which never
// gets destroyed (same as "on()" code in the tree.js).
$(treeSelector).on(eventname, handler);
},
/**
* Get the children of a competency.
*
* @param {Number} id The competency ID.
* @return {Array}
* @method getChildren
*/
getChildren: function(id) {
var children = [];
$.each(competencies, function(index, competency) {
if (competency.parentid == id) {
children.push(competency);
}
});
return children;
},
/**
* Get the competency framework id this model was initiliased with.
*
* @return {Number}
*/
getCompetencyFrameworkId: function() {
return competencyFrameworkId;
},
/**
* Get a competency by id
*
* @param {Number} id The competency id
* @return {Object}
*/
getCompetency: function(id) {
return competencies[id];
},
/**
* Get the competency level.
*
* @param {Number} id The competency ID.
* @return {Number}
*/
getCompetencyLevel: function(id) {
var competency = this.getCompetency(id),
level = competency.path.replace(/^\/|\/$/g, '').split('/').length;
return level;
},
/**
* Whether a competency has children.
*
* @param {Number} id The competency ID.
* @return {Boolean}
* @method hasChildren
*/
hasChildren: function(id) {
return this.getChildren(id).length > 0;
},
/**
* Does the competency have a rule?
*
* @param {Number} id The competency ID.
* @return {Boolean}
*/
hasRule: function(id) {
var comp = this.getCompetency(id);
if (comp) {
return comp.ruleoutcome != CompOutcomes.OUTCOME_NONE
&& comp.ruletype;
}
return false;
},
/**
* Reload all the page competencies framework competencies.
* @method reloadCompetencies
* @return {Promise}
*/
reloadCompetencies: function() {
return loadCompetencies('').fail(notification.exception);
},
/**
* Get all competencies for this framework.
*
* @return {Object[]}
*/
listCompetencies: function() {
return competencies;
},
};
});