MDL-50308 tool_lp: Big javascript cleanup

This includes:
* Move all JS modules from lib/amd to admin/tool/lp/amd
* Add all jsdocs
* fix all jshint warnings
* Rewrite the actionmenu wrapper to a real amd module
This commit is contained in:
Damyon Wiese 2015-05-14 13:35:38 +08:00 committed by Frederic Massart
parent d629323f72
commit 7e8d4dac9b
41 changed files with 1805 additions and 398 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
define(["core/ajax","core/notification","jquery"],function(a,b,c){var d=[],e=0,f=function(b){var f=c.Deferred();b="";var g=a.call([{methodname:"tool_lp_search_competencies",args:{searchtext:b,competencyframeworkid:e}}]);return g[0].done(function(a){d=[];var b=0;for(b=0;b<a.length;b++)d[a[b].id]=a[b];f.resolve(d)}).fail(function(a){f.reject(a)}),f.promise()};return{init:function(a){e=a,f("").fail(b.exception)},getCompetencyFrameworkId:function(){return e},getCompetency:function(a){return d[a]},listCompetencies:function(){return d},applySearch:function(a){return f(a)}}});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
define(["core/yui"],function(a){var b=function(b,c,d){this.yuiDialogue=null;var e=this;a.use("moodle-core-notification",function(){e.yuiDialogue=new M.core.dialogue({headerContent:b,bodyContent:c,draggable:!0,visible:!1,center:!0,modal:!0}),e.yuiDialogue.after("visibleChange",function(a){a.newVal&&d(e)}),e.yuiDialogue.show()})};return b.prototype.close=function(){this.yuiDialogue.hide(),this.yuiDialogue.destroy()},b.prototype.getContent=function(){return this.yuiDialogue.bodyNode.getDOMNode()},b});

View file

@ -1 +1 @@
define(["core/str","core/yui"],function(a,b){var c=function(a){var b=a.drag.get("node"),c=a.drop.get("node");this.callback(b.getDOMNode(),c.getDOMNode())};return{dragdrop:function(d,e,f,g,h,i,j,k){a.get_strings([{key:"emptydragdropregion",component:"moodle"},{key:"movecontent",component:"moodle"},{key:"tocontent",component:"moodle"}]).done(function(){b.use("moodle-core-dragdrop-reorder",function(){var a={callback:k};M.core.dragdrop_reorder({group:d,dragHandleText:e,sameNodeText:f,parentNodeText:g,sameNodeClass:h,parentNodeClass:i,dragHandleInsertClass:j,callback:b.bind(c,a)})})})}}});
define(["core/str","core/yui"],function(a,b){var c=function(a){var b=a.drag.get("node"),c=a.drop.get("node");this.callback(b.getDOMNode(),c.getDOMNode())};return{dragdrop:function(d,e,f,g,h,i,j,k){a.get_strings([{key:"emptydragdropregion",component:"moodle"},{key:"movecontent",component:"moodle"},{key:"tocontent",component:"moodle"}]).done(function(){b.use("moodle-tool_lp-dragdrop-reorder",function(){var a={callback:k};M.tool_lp.dragdrop_reorder({group:d,dragHandleText:e,sameNodeText:f,parentNodeText:g,sameNodeClass:h,parentNodeClass:i,dragHandleInsertClass:j,callback:b.bind(c,a)})})})}}});

View file

@ -1 +1 @@
define(["jquery","core/templates","core/ajax","core/notification"],function(a,b,c,d){var e=0,f=function(c,d){a('[data-region="managecompetencies"]').replaceWith(c),b.runTemplateJS(d)},g=function(a){b.render("tool_lp/manage_competency_frameworks_page",a).done(f).fail(d.exception)},h=function(){var a=c.call([{methodname:"tool_lp_delete_competency_framework",args:{id:e}},{methodname:"tool_lp_data_for_competency_frameworks_manage_page",args:[]}]);a[1].done(g).fail(d.exception)},i=function(b){b.preventDefault();var c=a(this).attr("data-frameworkid");e=c,d.confirm("Confirm",'Delete competency framework "blah"?',"Delete","Cancel",h)};return{init:function(){a('[data-region="managecompetencies"]').on("click",'[data-action="deletecompetencyframework"]',i)}}});
define(["jquery","core/templates","core/ajax","core/notification","core/str"],function(a,b,c,d,e){var f=0,g=function(c,d){a('[data-region="managecompetencies"]').replaceWith(c),b.runTemplateJS(d)},h=function(a){b.render("tool_lp/manage_competency_frameworks_page",a).done(g).fail(d.exception)},i=function(){var a=c.call([{methodname:"tool_lp_delete_competency_framework",args:{id:f}},{methodname:"tool_lp_data_for_competency_frameworks_manage_page",args:[]}]);a[1].done(h).fail(d.exception)},j=function(b){b.preventDefault();var g=a(this).attr("data-frameworkid");f=g;var h=c.call([{methodname:"tool_lp_read_competency_framework",args:{id:f}}]);h[0].done(function(a){e.get_strings([{key:"confirm",component:"tool_lp"},{key:"deletecompetencyframework",component:"tool_lp",param:a.shortname},{key:"delete",component:"tool_lp"},{key:"cancel",component:"tool_lp"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],i)}).fail(d.exception)}).fail(d.exception)};return{deleteHandler:j}});

View file

@ -1 +1 @@
define(["core/dragdrop-reorder","core/str","core/notification","jquery","core/ajax"],function(a,b,c,d,e){var f=function(a,b){var f=d(a).data("frameworkid"),g=d(b).data("frameworkid"),h=e.call([{methodname:"tool_lp_reorder_competency_framework",args:{from:f,to:g}}]);h[0].fail(c.exception)};return{init:function(){b.get_string("movecompetencyframework","tool_lp").done(function(b){a.dragdrop("movecompetencyframework",b,{identifier:"movecompetencyframework",component:"tool_lp"},{identifier:"movecompetencyframeworkafter",component:"tool_lp"},"drag-samenode","drag-parentnode","drag-handlecontainer",f)}).fail(c.exception)}}});
define(["jquery","core/str","core/notification","core/ajax","tool_lp/dragdrop-reorder"],function(a,b,c,d,e){var f=function(b,e){var f=a(b).data("frameworkid"),g=a(e).data("frameworkid"),h=d.call([{methodname:"tool_lp_reorder_competency_framework",args:{from:f,to:g}}]);h[0].fail(c.exception)};return{init:function(){b.get_string("movecompetencyframework","tool_lp").done(function(a){e.dragdrop("movecompetencyframework",a,{identifier:"movecompetencyframework",component:"tool_lp"},{identifier:"movecompetencyframeworkafter",component:"tool_lp"},"drag-samenode","drag-parentnode","drag-handlecontainer",f)}).fail(c.exception)}}});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
define(["jquery","core/templates","core/ajax","core/notification","core/str"],function(a,b,c,d,e){var f=0,g=0,h=function(c,d){a('[data-region="plans"]').replaceWith(c),b.runTemplateJS(d)},i=function(a){b.render("tool_lp/plans_page",a).done(h).fail(d.exception)},j=function(){var a=c.call([{methodname:"tool_lp_delete_plan",args:{id:f}},{methodname:"tool_lp_data_for_plans_page",args:{userid:g}}]);a[1].done(i).fail(d.exception)},k=function(b){b.preventDefault();var g=a(this).attr("data-planid");f=g;var h=c.call([{methodname:"tool_lp_read_plan",args:{id:f}}]);h[0].done(function(a){e.get_strings([{key:"confirm",component:"tool_lp"},{key:"deleteplan",component:"tool_lp",param:a.name},{key:"delete",component:"tool_lp"},{key:"cancel",component:"tool_lp"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],j)}).fail(d.exception)}).fail(d.exception)};return{init:function(){a('[data-region="plans"]').on("click",'[data-action="deleteplan"]',k),g=a('[data-region="plans"]').attr("data-userid")}}});

View file

@ -0,0 +1 @@
define(["jquery","core/templates","core/ajax","core/notification","core/str"],function(a,b,c,d,e){var f=0,g=function(c,d){a('[data-region="managetemplates"]').replaceWith(c),b.runTemplateJS(d)},h=function(a){b.render("tool_lp/manage_templates_page",a).done(g).fail(d.exception)},i=function(){var a=c.call([{methodname:"tool_lp_delete_template",args:{id:f}},{methodname:"tool_lp_data_for_templates_manage_page",args:[]}]);a[1].done(h).fail(d.exception)},j=function(b){b.preventDefault();var g=a(this).attr("data-templateid");f=g;var h=c.call([{methodname:"tool_lp_read_template",args:{id:f}}]);h[0].done(function(a){e.get_strings([{key:"confirm",component:"tool_lp"},{key:"deletetemplate",component:"tool_lp",param:a.shortname},{key:"delete",component:"tool_lp"},{key:"cancel",component:"tool_lp"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],i)}).fail(d.exception)}).fail(d.exception)};return{deleteHandler:j}});

View file

@ -0,0 +1 @@
define(["jquery","core/str","core/notification","core/ajax","tool_lp/dragdrop-reorder"],function(a,b,c,d,e){var f=function(b,e){var f=a(b).data("templateid"),g=a(e).data("templateid"),h=d.call([{methodname:"tool_lp_reorder_template",args:{from:f,to:g}}]);h[0].fail(c.exception)};return{init:function(){b.get_string("movetemplate","tool_lp").done(function(a){e.dragdrop("movetemplate",a,{identifier:"movetemplate",component:"tool_lp"},{identifier:"movetemplateafter",component:"tool_lp"},"drag-samenode","drag-parentnode","drag-handlecontainer",f)}).fail(c.exception)}}});

1
admin/tool/lp/amd/build/tree.min.js vendored Normal file
View file

@ -0,0 +1 @@
define(["jquery","core/url"],function(a,b){var c=a('<img alt="" src="'+b.imageUrl("t/expanded")+'"/>'),d=a('<img alt="" src="'+b.imageUrl("t/collapsed")+'"/>'),e=function(b,c){this.treeRoot=a(b),this.items=this.treeRoot.find("li"),this.parents=this.treeRoot.find("li:has(ul)"),this.visibleItems=null,this.activeItem=null,this.selectCallback=c,this.keys={tab:9,enter:13,space:32,pageup:33,pagedown:34,end:35,home:36,left:37,up:38,right:39,down:40,asterisk:106},this.init(),this.bindEventHandlers()};return e.prototype.init=function(){this.parents.attr("aria-expanded","true"),this.parents.prepend(c.clone()),this.items.attr("role","tree-item"),this.items.attr("tabindex","-1"),this.parents.attr("role","group"),this.treeRoot.attr("role","tree"),this.visibleItems=this.treeRoot.find("li")},e.prototype.expandGroup=function(a){var b=a.children("ul");b.show().attr("aria-hidden","false"),a.attr("aria-expanded","true"),a.children("img").attr("src",c.attr("src")),this.visibleItems=this.treeRoot.find("li:visible")},e.prototype.collapseGroup=function(a){var b=a.children("ul");b.hide().attr("aria-hidden","true"),a.attr("aria-expanded","false"),a.children("img").attr("src",d.attr("src")),this.visibleItems=this.treeRoot.find("li:visible")},e.prototype.toggleGroup=function(a){"true"==a.attr("aria-expanded")?this.collapseGroup(a):this.expandGroup(a)},e.prototype.updateFocus=function(a){this.items.attr("aria-selected","false").attr("tabindex","-1"),a.attr("aria-selected","true").attr("tabindex",0),this.selectCallback(a)},e.prototype.handleKeyDown=function(b,c){var d=this.visibleItems.index(b);if(c.altKey||c.ctrlKey||c.shiftKey&&c.keyCode!=this.keys.tab)return!0;switch(c.keyCode){case this.keys.home:return this.activeItem=this.parents.first(),this.activeItem.focus(),c.stopPropagation(),!1;case this.keys.end:return this.activeItem=this.visibleItems.last(),this.activeItem.focus(),c.stopPropagation(),!1;case this.keys.enter:case this.keys.space:return b.has("ul")&&this.toggleGroup(b,!0),c.stopPropagation(),!1;case this.keys.left:if(b.has("ul")&&"true"==b.attr("aria-expanded"))this.collapseGroup(b);else{var e=b.parent(),f=e.parent();this.activeItem=f,this.activeItem.focus()}return c.stopPropagation(),!1;case this.keys.right:return b.has("ul")&&"false"==b.attr("aria-expanded")?this.expandGroup(b):(this.activeItem=b.children("ul").children("li").first(),this.activeItem.focus()),c.stopPropagation(),!1;case this.keys.up:if(d>0){var g=this.visibleItems.eq(d-1);this.activeItem=g,g.focus()}return c.stopPropagation(),!1;case this.keys.down:if(d<this.visibleItems.length-1){var h=this.visibleItems.eq(d+1);this.activeItem=h,h.focus()}return c.stopPropagation(),!1;case this.keys.asterisk:var i=this;return this.parents.each(function(){i.expandGroup(a(this))}),c.stopPropagation(),!1}return!0},e.prototype.handleKeyPress=function(a,b){if(b.altKey||b.ctrlKey||b.shiftKey)return!0;switch(b.keyCode){case this.keys.tab:return!0;case this.keys.enter:case this.keys.home:case this.keys.end:case this.keys.left:case this.keys.right:case this.keys.up:case this.keys.down:return b.stopPropagation(),!1;default:var c=String.fromCharCode(b.which),d=!1,e=this.visibleItems.index(a),f=this.visibleItems.length,g=e+1;for(g==f&&(g=0);g!=e;){var h=this.visibleItems.eq(g),i=h.text().charAt(0);if(h.has("ul")&&(i=h.find("span").text().charAt(0)),i.toLowerCase()==c){d=!0;break}g+=1,g==f&&(g=0)}return d===!0&&(this.activeItem=this.visibleItems.eq(g),this.activeItem.focus()),b.stopPropagation(),!1}return!0},e.prototype.handleDblClick=function(a,b){return b.altKey||b.ctrlKey||b.shiftKey?!0:(this.activeItem=a,this.updateFocus(a),this.toggleGroup(a),b.stopPropagation(),!1)},e.prototype.handleClick=function(a,b){return b.altKey||b.ctrlKey||b.shiftKey?!0:(this.activeItem=a,this.updateFocus(a),b.stopPropagation(),!1)},e.prototype.handleBlur=function(){return!0},e.prototype.handleFocus=function(a){return null===this.activeItem&&(this.activeItem=a),this.updateFocus(this.activeItem),!0},e.prototype.bindEventHandlers=function(){var b=this;this.parents.dblclick(function(c){return b.handleDblClick(a(this),c)}),this.items.click(function(c){return b.handleClick(a(this),c)}),this.items.keydown(function(c){return b.handleKeyDown(a(this),c)}),this.items.keypress(function(c){return b.handleKeyPress(a(this),c)}),this.items.focus(function(c){return b.handleFocus(a(this),c)}),this.items.blur(function(c){return b.handleBlur(a(this),c)})},e});

View file

@ -21,14 +21,21 @@
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dialogue', 'core/str', 'core/tree', 'core/dragdrop-reorder'],
function($, notification, ajax, templates, dialogue, str, ariatree, dragdrop) {
define(['jquery',
'core/notification',
'core/ajax',
'core/templates',
'tool_lp/dialogue',
'core/str',
'tool_lp/tree',
'tool_lp/dragdrop-reorder'],
function($, notification, ajax, templates, Dialogue, str, Ariatree, dragdrop) {
/**
* Constructor
*
* @param {int} itemid
* @param {string} itemtype
* @param {Number} itemid
* @param {String} itemtype
*/
var competencies = function(itemid, itemtype) {
this.itemid = itemid;
@ -41,7 +48,7 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
loadframeworks[0].done(function(frameworks) {
localthis.frameworks = frameworks;
if (frameworks.length == 0) {
if (frameworks.length === 0) {
templates.render('tool_lp/no_frameworks_warning', {})
.done(function(html) {
$('[data-region="actions"]').append(html);
@ -55,6 +62,10 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
}).fail(notification.exception);
};
/**
* Initialise the drag/drop code.
* @method registerDragDrop
*/
competencies.prototype.registerDragDrop = function() {
var localthis = this;
// Init this module.
@ -75,20 +86,32 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
};
/**
* Handle a drop from a drag/drop operation.
*
* @method handleDrop
* @param {Node} drag The dragged node.
* @param {Node} drop The dropped on node.
*/
competencies.prototype.handleDrop = function(drag, drop) {
var fromid = $(drag).data('id');
var toid = $(drop).data('id');
var localthis = this;
var requests = [];
if (localthis.itemtype == 'course') {
var requests = ajax.call([
{ methodname: 'tool_lp_reorder_course_competency',
args: { courseid: localthis.itemid, competencyidfrom: fromid, competencyidto: toid } }
]);
requests = ajax.call([
{
methodname: 'tool_lp_reorder_course_competency',
args: { courseid: localthis.itemid, competencyidfrom: fromid, competencyidto: toid }
}
]);
} else if (localthis.itemtype == 'template') {
var requests = ajax.call([
{ methodname: 'tool_lp_reorder_template_competency',
args: { templateid: localthis.itemid, competencyidfrom: fromid, competencyidto: toid } }
requests = ajax.call([
{
methodname: 'tool_lp_reorder_template_competency',
args: { templateid: localthis.itemid, competencyidfrom: fromid, competencyidto: toid }
}
]);
} else {
return null;
@ -97,6 +120,12 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
requests[0].fail(notification.exception);
};
/**
* Get the search text from the input field and reload the tree based on the search.
*
* @method applyFilter
* @param {Event} e The event that triggered the button.
*/
competencies.prototype.applyFilter = function(e) {
e.preventDefault();
var localthis = this;
@ -118,18 +147,28 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
}
}
framework.selected = true;
var context = { framework: framework, frameworks: localthis.frameworks, competencies: competencies, search: searchText };
var context = {
framework: framework,
frameworks: localthis.frameworks,
competencies: competencies,
search: searchText
};
templates.render('tool_lp/link_course_competencies', context).done(function(html) {
$('[data-region="competencylinktree"]').replaceWith(html);
localthis.initLinkCourseCompetencies();
}).fail(notification.exception);;
}).fail(notification.exception);
}).fail(notification.exception);
};
/**
* The link course competencies popup was just opened and we need to initialise it.
*
* @method initLinkCourseCompetencies
*/
competencies.prototype.initLinkCourseCompetencies = function() {
var localthis = this;
var competencytree = new ariatree('[data-enhance=linktree]', function(target) {
new Ariatree('[data-enhance=linktree]', function(target) {
localthis.selectedCompetency = target.data('id');
});
@ -148,6 +187,10 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
localthis.popup.close();
});
$('[data-region="competencylinktree"] [data-action="add"]').click(function(e) {
var requests = [],
pagerender = '',
pageregion = '';
e.preventDefault();
if (!localthis.selectedCompetency) {
return;
@ -157,23 +200,23 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
// Add the link and reload the page template.
if (localthis.itemtype == 'course') {
var requests = ajax.call([
requests = ajax.call([
{ methodname: 'tool_lp_add_competency_to_course',
args: { courseid: localthis.itemid, competencyid: localthis.selectedCompetency } },
{ methodname: 'tool_lp_data_for_course_competencies_page',
args: { courseid: localthis.itemid } }
]);
var pagerender = 'tool_lp/course_competencies_page';
var pageregion = 'coursecompetenciespage';
pagerender = 'tool_lp/course_competencies_page';
pageregion = 'coursecompetenciespage';
} else if (localthis.itemtype == 'template') {
var requests = ajax.call([
requests = ajax.call([
{ methodname: 'tool_lp_add_competency_to_template',
args: { templateid: localthis.itemid, competencyid: localthis.selectedCompetency } },
{ methodname: 'tool_lp_data_for_template_competencies_page',
args: { templateid: localthis.itemid } }
]);
var pagerender = 'tool_lp/template_competencies_page';
var pageregion = 'templatecompetenciespage';
pagerender = 'tool_lp/template_competencies_page';
pageregion = 'templatecompetenciespage';
} else {
return null;
}
@ -188,35 +231,44 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
});
};
/**
* Register the javascript event handlers for this page.
*
* @method registerEvents
*/
competencies.prototype.registerEvents = function() {
var localthis = this;
$('[data-region="actions"] button').click(function(e) {
return localthis.openCompetencySelector.call(localthis, e);
});
$('[data-action="delete-competency-link"]').click(function(e) {
var requests = [],
pagerender = '',
pageregion = '';
e.preventDefault();
var deleteid = $(e.target).closest('[data-id]').data('id');
// Delete the link and reload the page template.
if (localthis.itemtype == 'course') {
var requests = ajax.call([
requests = ajax.call([
{ methodname: 'tool_lp_remove_competency_from_course',
args: { courseid: localthis.itemid, competencyid: deleteid } },
{ methodname: 'tool_lp_data_for_course_competencies_page',
args: { courseid: localthis.itemid } }
]);
var pagerender = 'tool_lp/course_competencies_page';
var pageregion = 'coursecompetenciespage';
pagerender = 'tool_lp/course_competencies_page';
pageregion = 'coursecompetenciespage';
} else if (localthis.itemtype == 'template') {
var requests = ajax.call([
requests = ajax.call([
{ methodname: 'tool_lp_remove_competency_from_template',
args: { templateid: localthis.itemid, competencyid: deleteid } },
{ methodname: 'tool_lp_data_for_template_competencies_page',
args: { templateid: localthis.itemid } }
]);
var pagerender = 'tool_lp/template_competencies_page';
var pageregion = 'templatecompetenciespage';
pagerender = 'tool_lp/template_competencies_page';
pageregion = 'templatecompetenciespage';
}
requests[1].done(function(context) {
@ -228,6 +280,13 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
});
};
/**
* Turn the flat list of competencies into a tree.
*
* @method addCompetencyChildren
* @param {Object} parent The current parent node
* @param {Object[]} competencies The flat list of all nodes.
*/
competencies.prototype.addCompetencyChildren = function(parent, competencies) {
var i;
@ -242,6 +301,12 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
}
};
/**
* Get the search text from the input, and reload the tree.
*
* @method searchCompetencies
* @return {promise} When resolved it will contain the tree of competencies.
*/
competencies.prototype.searchCompetencies = function() {
var localthis = this;
var deferred = $.Deferred();
@ -253,7 +318,7 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
var framework = $('[data-action="chooseframework"]');
var frameworkid = localthis.frameworks[0].id;
if (framework.length) {
var frameworkid = framework.val();
frameworkid = framework.val();
}
var loadcompetencies = ajax.call([
@ -265,7 +330,7 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
var i, competenciestree = [];
for (i = 0; i < competencies.length; i++) {
var onecompetency = competencies[i];
if (onecompetency.parentid == 0) {
if (onecompetency.parentid === "0") {
onecompetency.children = [];
onecompetency.haschildren = 0;
competenciestree[competenciestree.length] = onecompetency;
@ -278,6 +343,11 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
return deferred.promise();
};
/**
* Open a popup to choose competencies.
*
* @method openCompetencySelector
*/
competencies.prototype.openCompetencySelector = function(e) {
e.preventDefault();
var localthis = this;
@ -287,16 +357,18 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates', 'core/dial
framework.selected = true;
var context = { framework: framework, frameworks: localthis.frameworks, competencies: competencies, search: '' };
templates.render('tool_lp/link_course_competencies', context).done(function(html) {
str.get_string('linkcompetencies', 'tool_lp').done(function(title) {;
localthis.popup = new dialogue(
str.get_string('linkcompetencies', 'tool_lp').done(function(title) {
localthis.popup = new Dialogue(
title,
html, // The link UI.
(function() {localthis.initLinkCourseCompetencies.call(localthis)})
function() {
localthis.initLinkCourseCompetencies.call(localthis);
}
);
}).fail(notification.exception);
}).fail(notification.exception);;
}).fail(notification.exception);
}).fail(notification.exception);
};
return /** @alias module:core/tree */ competencies;
return /** @alias module:tool_lp/coursecompetencies */ competencies;
});

View file

@ -16,39 +16,55 @@
/**
* Handle selection changes and actions on the competency tree.
*
* @module tool_lp/competencyselect
* @module tool_lp/competencyactions
* @package tool_lp
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str', 'core/ajax', 'core/dragdrop-reorder', 'core/tree', 'core/dialogue', 'core/menu'],
function($, url, templates, notification, str, ajax, dragdrop, ariatree, dialogue, menu) {
define(['jquery',
'core/url',
'core/templates',
'core/notification',
'core/str',
'core/ajax',
'tool_lp/dragdrop-reorder',
'tool_lp/tree',
'tool_lp/dialogue',
'tool_lp/menubar'],
function($, url, templates, notification, str, ajax, dragdrop, Ariatree, Dialogue, menubar) {
// Private variables and functions.
/** @var {Object} treeModel - This is an object representing the nodes in the tree. */
var treeModel = null;
/** @var {Node} moveSource - The start of a drag operation */
var moveSource = null;
/** @var {Node} moveTarget - The end of a drag operation */
var moveTarget = null;
var addHandler = function(e) {
e.preventDefault();
/**
* Respond to choosing the "Add" menu item for the selected node in the tree.
* @method addHandler
*/
var addHandler = function() {
var parent = $('[data-region="competencyactions"]').data('competency');
var params = {
competencyframeworkid : treeModel.getCompetencyFrameworkId()
};
if (parent == null) {
// We are adding at the root node.
} else {
if (parent !== null) {
// We are adding at a sub node.
params['parentid'] = parent.id;
params.parentid = parent.id;
}
var queryparams = $.param(params);
var actionurl = url.relativeUrl('/admin/tool/lp/editcompetency.php?' + queryparams);
window.location = actionurl;
};
/**
* A source and destination has been chosen - so time to complete a move.
* @method doMove
*/
var doMove = function() {
if (typeof (moveTarget) === "undefined") {
// This is a top level node.
@ -70,16 +86,27 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
requests[1].done(reloadPage).fail(notification.exception);
};
/**
* A move competency popup was opened - initialise the aria tree in it.
* @method initMovePopup
* @param {dialogue} The tool_lp/dialogue that was created.
*/
var initMovePopup = function(popup) {
var movetree = new ariatree('[data-enhance=movetree]', function(target) {
new Ariatree('[data-enhance=movetree]', function(target) {
moveTarget = $(target).data('id');
});
var body = $(popup.getContent());
body.on('click', '[data-action="move"]', function(e) { popup.close(); doMove() });
body.on('click', '[data-action="cancel"]', function(e) { popup.close(); });
body.on('click', '[data-action="move"]', function() { popup.close(); doMove(); });
body.on('click', '[data-action="cancel"]', function() { popup.close(); });
};
/**
* Turn a flat list of competencies into a tree structure (recursive).
* @method addCompetencyChildren
* @param {Object} parent The current parent node in the tree
* @param {Object[]} competencies The flat list of competencies
*/
var addCompetencyChildren = function(parent, competencies) {
var i;
@ -94,8 +121,11 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
}
};
var moveHandler = function(e) {
e.preventDefault();
/**
* A node was chosen and "Move" was selected from the menu. Open a popup to select the target.
* @method moveHandler
*/
var moveHandler = function() {
var competency = $('[data-region="competencyactions"]').data('competency');
// Remember what we are moving.
@ -124,7 +154,7 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
var i, competenciestree = [];
for (i = 0; i < competencies.length; i++) {
var onecompetency = competencies[i];
if (onecompetency.parentid == 0) {
if (onecompetency.parentid === "0") {
onecompetency.children = [];
onecompetency.haschildren = 0;
competenciestree[competenciestree.length] = onecompetency;
@ -132,7 +162,7 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
}
}
var strings = str.get_strings([
str.get_strings([
{ key: 'movecompetency', component: 'tool_lp', param: competency.shortname },
{ key: 'move', component: 'tool_lp' },
{ key: 'cancel', component: 'tool_lp' }
@ -145,7 +175,7 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
templates.render('tool_lp/competencies_move_tree', context)
.done(function(tree) {
var popup = new dialogue(
new Dialogue(
strings[0], // Move competency x.
tree, // The move tree.
initMovePopup
@ -159,8 +189,11 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
};
var editHandler = function(e) {
e.preventDefault();
/**
* Edit the selected competency.
* @method editHandler
*/
var editHandler = function() {
var competency = $('[data-region="competencyactions"]').data('competency');
var params = {
@ -174,6 +207,10 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
window.location = actionurl;
};
/**
* Re-render the page with the latest data.
* @method reloadPage
*/
var reloadPage = function(context) {
templates.render('tool_lp/manage_competencies_page', context)
.done(function(newhtml, newjs) {
@ -183,6 +220,10 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
.fail(notification.exception);
};
/**
* Perform a search and render the page with the new search results.
* @method updateSearchHandler
*/
var updateSearchHandler = function(e) {
e.preventDefault();
@ -196,6 +237,10 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
requests[0].done(reloadPage).fail(notification.exception);
};
/**
* Move a competency "up". This only affects the sort order within the same branch of the tree.
* @method moveUpHandler
*/
var moveUpHandler = function() {
// We are chaining ajax requests here.
var competency = $('[data-region="competencyactions"]').data('competency');
@ -210,6 +255,10 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
requests[1].done(reloadPage).fail(notification.exception);
};
/**
* Move a competency "down". This only affects the sort order within the same branch of the tree.
* @method moveDownHandler
*/
var moveDownHandler = function() {
// We are chaining ajax requests here.
var competency = $('[data-region="competencyactions"]').data('competency');
@ -224,10 +273,12 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
requests[1].done(reloadPage).fail(notification.exception);
};
var seeCoursesHandler = function(e) {
e.preventDefault();
/**
* Open a dialogue to show all the courses using the selected competency.
* @method seeCoursesHandler
*/
var seeCoursesHandler = function() {
var competency = $('[data-region="competencyactions"]').data('competency');
var localthis = this;
var requests = ajax.call([{
methodname: 'tool_lp_list_courses_using_competency',
@ -241,7 +292,7 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
};
templates.render('tool_lp/linked_courses_summary', context).done(function(html) {
str.get_string('linkedcourses', 'tool_lp').done(function (linkedcourses) {
var popup = new dialogue(
new Dialogue(
linkedcourses, // Title.
html, // The linked courses.
initMovePopup
@ -249,8 +300,12 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
}).fail(notification.exception);
}).fail(notification.exception);
}).fail(notification.exception);
}
};
/**
* Delete a competency.
* @method doDelete
*/
var doDelete = function() {
// We are chaining ajax requests here.
var competency = $('[data-region="competencyactions"]').data('competency');
@ -265,14 +320,17 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
requests[1].done(reloadPage).fail(notification.exception);
};
var deleteHandler = function(e) {
e.preventDefault();
/**
* Show a confirm dialogue before deleting a competency.
* @method deleteHandler
*/
var deleteHandler = function() {
var competency = $('[data-region="competencyactions"]').data('competency');
templates.render('tool_lp/competency_summary', competency)
.done(function(html) {
var strings = str.get_strings([
str.get_strings([
{ key: 'confirm', component: 'tool_lp' },
{ key: 'deletecompetency', component: 'tool_lp', param: html },
{ key: 'delete', component: 'tool_lp' },
@ -290,25 +348,45 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
};
/**
* HTML5 implementation of drag/drop (there is an accesible alternative in the menus).
* @method dragStart
*/
var dragStart = function(e) {
e.originalEvent.dataTransfer.setData('text', $(e.target).data('id'));
};
/**
* HTML5 implementation of drag/drop (there is an accesible alternative in the menus).
* @method allowDrop
*/
var allowDrop = function(e) {
e.originalEvent.dataTransfer.dropEffect = 'move';
e.preventDefault();
};
/**
* HTML5 implementation of drag/drop (there is an accesible alternative in the menus).
* @method dragEnter
*/
var dragEnter = function(e) {
e.preventDefault();
$(this).addClass('currentdragtarget');
}
};
/**
* HTML5 implementation of drag/drop (there is an accesible alternative in the menus).
* @method dragLeave
*/
var dragLeave = function(e) {
e.preventDefault();
$(this).removeClass('currentdragtarget');
}
};
/**
* HTML5 implementation of drag/drop (there is an accesible alternative in the menus).
* @method dropOver
*/
var dropOver = function(e) {
e.preventDefault();
moveSource = e.originalEvent.dataTransfer.getData('text');
@ -319,20 +397,27 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
};
return {
/**
* Initialise this page (attach event handlers etc).
*
* @method init
* @param {Object} model The tree model provides some useful functions for loading and searching competencies.
*/
init: function(model) {
treeModel = model;
str.get_string('edit', 'core').done(function (edit) {
menu.menu(edit, '.competencyactionsmenu');
$('[data-region="competencyactions"]').on('click', '[data-action="add"]', addHandler);
$('[data-region="competencyactions"]').on('click', '[data-action="edit"]', editHandler);
$('[data-region="competencyactions"]').on('click', '[data-action="delete"]', deleteHandler);
$('[data-region="competencyactions"]').on('click', '[data-action="move"]', moveHandler);
$('[data-region="competencyactions"]').on('click', '[data-action="moveup"]', moveUpHandler);
$('[data-region="competencyactions"]').on('click', '[data-action="movedown"]', moveDownHandler);
$('[data-region="competencyactions"]').on('click', '[data-action="linkedcourses"]', seeCoursesHandler);
$('[data-region="competencyactions"]').on('click', addHandler);
menubar.enhance('.competencyactionsmenu', {
'[data-action="edit"]': editHandler,
'[data-action="delete"]': deleteHandler,
'[data-action="move"]': moveHandler,
'[data-action="moveup"]': moveUpHandler,
'[data-action="movedown"]': moveDownHandler,
'[data-action="linkedcourses"]': seeCoursesHandler
});
$('[data-region="competencyactionsmenu"]').hide();
}).fail(notification.exception);
$('[data-region="filtercompetencies"]').on('submit', updateSearchHandler);
// Simple html5 drag drop because we already added an accessible alternative.
$('[data-region="managecompetencies"] li').on('dragstart', dragStart);
@ -341,9 +426,14 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
$('[data-region="managecompetencies"] li').on('dragleave', dragLeave);
$('[data-region="managecompetencies"] li').on('drop', dropOver);
},
// Public variables and functions.
/**
* Handler when a node in the aria tree is selected.
* @method selectionChanged
*/
selectionChanged: function(node) {
var id = $(node).data('id');
menubar.closeAll();
if (typeof id === "undefined") {
// Assume this is the root of the tree.
// Here we are only getting the text from the top of the tree, to do it we clone the tree,
@ -355,6 +445,7 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
} else {
var competency = treeModel.getCompetency(id);
$('[data-region="competencyactionsmenu"]').show();
templates.render('tool_lp/competency_summary', competency)
.done(function(html) {
$('[data-region="competencyinfo"]').html(html);
@ -362,7 +453,6 @@ define(['jquery', 'core/url', 'core/templates', 'core/notification', 'core/str',
$('[data-region="competencyactions"]').data('competency', competency);
$('[data-region="competencyactions"] [data-action="add"]').removeAttr("disabled");
$('[data-region="competencyactionsmenu"]').css('display', 'inline-block');
}
}

View file

@ -23,10 +23,17 @@
*/
define(['core/ajax', 'core/notification', 'jquery'], function(ajax, notification, $) {
// Private variables and functions.
/** @var {Object[]} competencies - Cached list of competencies */
var competencies = [];
/** @var {Number} competencyFrameworkId - The current framework id */
var competencyFrameworkId = 0;
/**
* 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();
searchtext = '';
@ -52,25 +59,52 @@
};
return {
return /** @alias module:tool_lp/competencytree */ {
// Public variables and functions.
/**
* Initialise the tree.
*
* @param {Number} id The competency id.
*/
init: function(id) {
competencyFrameworkId = id;
loadCompetencies('').fail(notification.exception);
},
/**
* Get the competency framework id this model was initiliased with.
*
* @return {Number}
*/
getCompetencyFrameworkId: function() {
return competencyFrameworkId;
},
// Public variables and functions.
/**
* Get a competency by id
*
* @param {Number} id The competency id
* @return {Object}
*/
getCompetency: function(id) {
return competencies[id];
},
/**
* Get all competencies for this framework.
*
* @return {Object[]}
*/
listCompetencies: function() {
return competencies;
},
/**
* Reload the list of competencies, filtered by the search text.
*
* @param {String} searchtext The text to filter by.
* @return {Object[]} The filtered competency list.
*/
applySearch: function(searchtext) {
return loadCompetencies(searchtext);
}

View file

@ -17,8 +17,8 @@
* Wrapper for the YUI M.core.notification class. Allows us to
* use the YUI version in AMD code until it is replaced.
*
* @module core/dialogue
* @package core
* @module tool_lp/dialogue
* @package tool_lp
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@ -28,8 +28,8 @@ define(['core/yui'], function(Y) {
/**
* Constructor
*
* @param {string} title Title for the window.
* @param {string} content The content for the window.
* @param {String} title Title for the window.
* @param {String} content The content for the window.
* @param {function} afterShow Callback executed after the window is opened.
*/
var dialogue = function(title, content, afterShow) {
@ -72,5 +72,5 @@ define(['core/yui'], function(Y) {
return this.yuiDialogue.bodyNode.getDOMNode();
};
return /** @alias module:core/dialogue */ dialogue;
return /** @alias module:tool_lp/dialogue */ dialogue;
});

View file

@ -14,11 +14,10 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Wrapper for the YUI M.core.dragdrop class. Allows us to
* use the YUI version in AMD code until it is replaced.
* Drag and drop reorder via HTML5.
*
* @module core/dragdrop-reorder
* @package core
* @module tool_lp/dragdrop-reorder
* @package tool_lp
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@ -37,18 +36,18 @@ define(['core/str', 'core/yui'], function(str, Y) {
this.callback(dragNode.getDOMNode(), dropNode.getDOMNode());
};
return /** @alias module:core/dragdrop-reorder */ {
return /** @alias module:tool_lp/dragdrop-reorder */ {
// Public variables and functions.
/**
* Create an instance of M.core.dragdrop
* Create an instance of M.tool_lp.dragdrop
*
* @param {string} group Unique string to identify this interaction.
* @param {string} dragHandleText Alt text for the drag handle.
* @param {string} sameNodeText Used in keyboard drag drop for the list of items target.
* @param {string} parentNodeText Used in keyboard drag drop for the parent target.
* @param {string} sameNodeClass class used to find the each of the list of items.
* @param {string} parentNodeClass class used to find the container for the list of items.
* @param {string} dragHandleInsertClass class used to find the location to insert the drag handles.
* @param {String} group Unique string to identify this interaction.
* @param {String} dragHandleText Alt text for the drag handle.
* @param {String} sameNodeText Used in keyboard drag drop for the list of items target.
* @param {String} parentNodeText Used in keyboard drag drop for the parent target.
* @param {String} sameNodeClass class used to find the each of the list of items.
* @param {String} parentNodeClass class used to find the container for the list of items.
* @param {String} dragHandleInsertClass class used to find the location to insert the drag handles.
* @param {function} callback Drop hit handler.
*/
dragdrop: function(group,
@ -66,12 +65,12 @@ define(['core/str', 'core/yui'], function(str, Y) {
{ key: 'movecontent', component: 'moodle' },
{ key: 'tocontent', component: 'moodle' },
]).done( function () {
Y.use('moodle-core-dragdrop-reorder', function () {
Y.use('moodle-tool_lp-dragdrop-reorder', function () {
var context = {
callback: callback
};
M.core.dragdrop_reorder({
M.tool_lp.dragdrop_reorder({
group: group,
dragHandleText: dragHandleText,
sameNodeText: sameNodeText,

View file

@ -30,8 +30,8 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
/**
* Callback to replace the dom element with the rendered template.
*
* @param {string} newhtml The new html to insert.
* @param {string} newjs The new js to run.
* @param {String} newhtml The new html to insert.
* @param {String} newjs The new js to run.
*/
var updatePage = function(newhtml, newjs) {
$('[data-region="managecompetencies"]').replaceWith(newhtml);
@ -81,7 +81,7 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
}]);
requests[0].done(function(framework) {
var strings = str.get_strings([
str.get_strings([
{ key: 'confirm', component: 'tool_lp' },
{ key: 'deletecompetencyframework', component: 'tool_lp', param: framework.shortname },
{ key: 'delete', component: 'tool_lp' },
@ -100,19 +100,14 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
};
return {
return /** @alias module:tool_lp/frameworkdelete */ {
// Public variables and functions.
/**
* Initialise this plugin. Just attaches some event handlers to the delete entries in the menu.
*/
init: function() {
// Init this module.
$('[data-region="managecompetencies"]').on(
"click",
'[data-action="deletecompetencyframework"]',
confirmDelete
);
}
/**
* Expose the event handler for delete.
* @method deleteHandler
* @param {Event} e
*/
deleteHandler: confirmDelete
};
});

View file

@ -16,22 +16,23 @@
/**
* Move competency frameworks via ajax.
*
* @module tool_lp/frameworkdelete
* @module tool_lp/frameworkmove
* @package tool_lp
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['core/dragdrop-reorder',
define(['jquery',
'core/str',
'core/notification',
'jquery',
'core/ajax'],
function(dragdrop, str, notification, $, ajax) {
'core/ajax',
'tool_lp/dragdrop-reorder'],
function($, str, notification, ajax, dragdrop) {
// Private variables and functions.
/**
* Handle a drop on a node.
*
* @method handleDrop
* @param {DOMNode} drag
* @param {DOMNode} drop
*/
@ -47,10 +48,11 @@ define(['core/dragdrop-reorder',
};
return {
return /** @alias module:tool_lp/frameworkmove */ {
// Public variables and functions.
/**
* Initialise this plugin. It loads some strings, then adds the drag/drop functions.
* @method init
*/
init: function() {
// Init this module.

View file

@ -0,0 +1,831 @@
// 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/>.
/**
* Aria menubar functionality. Enhances a simple nested list structure into a full aria widget.
* Based on the open ajax example: http://oaa-accessibility.org/example/26/
*
* @module tool_lp/menubar
* @package tool_lp
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery'], function($) {
/**
* Close all open submenus anywhere in the page (there should only ever be one open at a time).
*
* @method closeAllSubMenus
*/
var closeAllSubMenus = function() {
$('.tool-lp-menu .tool-lp-sub-menu').attr('aria-hidden', 'true');
};
/**
* Constructor
*
* @param {$} Jquery collection matching the root of the menu.
* @param {Function[]} handlers, called when a menu item is chosen.
*/
var Menubar = function(menuRoot, handlers) {
// Setup private class variables.
this.menuRoot = menuRoot;
this.handlers = handlers;
this.rootMenus = this.menuRoot.children('li');
this.subMenus = this.rootMenus.children('ul');
this.subMenuItems = this.subMenus.children('li');
this.allItems = this.rootMenus.add(this.subMenuItems);
this.activeItem = null;
this.isChildOpen = false;
this.keys = {
tab: 9,
enter: 13,
esc: 27,
space: 32,
left: 37,
up: 38,
right: 39,
down: 40
};
this.addAriaAttributes();
// Add the event listeners.
this.addEventListeners();
};
/**
* Open a submenu, first it closes all other sub-menus and sets the open direction.
* @method openSubMenu
* @param {Node} menu
*/
Menubar.prototype.openSubMenu = function(menu) {
this.setOpenDirection();
closeAllSubMenus();
menu.attr('aria-hidden', 'false');
};
/**
* Bind the event listeners to the DOM
* @method addEventListeners
*/
Menubar.prototype.addEventListeners = function() {
var currentThis = this;
// Hovers.
this.subMenuItems.mouseenter(function() {
$(this).addClass('menu-hover');
return true;
});
this.subMenuItems.mouseout(function() {
$(this).removeClass('menu-hover');
return true;
});
// Mouse listeners.
this.allItems.click(function(e) {
return currentThis.handleClick($(this), e);
});
// Key listeners.
this.allItems.keydown(function(e) {
return currentThis.handleKeyDown($(this), e);
});
this.allItems.focus(function() {
return currentThis.handleFocus($(this));
});
this.allItems.blur(function() {
return currentThis.handleBlur($(this));
});
};
/**
* Process click events for the top menus.
*
* @method handleClick
* @param {Object} item is the jquery object of the item firing the event
* @param {Event} e is the associated event object
* @return boolean Returns false
*/
Menubar.prototype.handleClick = function(item, e) {
var parentUL = item.parent();
if (parentUL.is('.tool-lp-menu')) {
// Toggle the child menu open/closed.
if (item.children('ul').first().attr('aria-hidden') == 'true') {
this.openSubMenu(item.children('ul').first());
} else {
item.children('ul').first().attr('aria-hidden', 'true');
}
e.stopPropagation();
} else {
// Remove hover and focus styling.
this.allItems.removeClass('menu-hover menu-focus');
// Close the menu.
this.menuRoot.find('ul').not('.root-level').attr('aria-hidden','true');
// Follow any link, or call the click handlers.
var anchor = item.find('a').first();
var clickEvent = new $.Event('click');
clickEvent.target = anchor;
var eventHandled = false;
if (this.handlers) {
$.each(this.handlers, function(selector, handler) {
if (eventHandled) {
return false;
}
if (item.find(selector).length > 0) {
var callable = $.proxy(handler, anchor);
// False means stop propogatting events.
eventHandled = (callable(clickEvent) === false) || clickEvent.isDefaultPrevented();
}
});
}
if (!eventHandled) {
window.location.href = anchor.attr('href');
}
return true;
}
return false;
};
/*
* Process focus events for the menu.
*
* @method handleFocus
* @param {Object} item is the jquery object of the item firing the event
* @return boolean Returns false
*/
Menubar.prototype.handleFocus = function(item) {
// If activeItem is null, we are getting focus from outside the menu. Store
// the item that triggered the event.
if (this.activeItem === null) {
this.activeItem = item;
} else if (item[0] != this.activeItem[0]) {
return true;
}
// Get the set of jquery objects for all the parent items of the active item.
var parentItems = this.activeItem.parentsUntil('ul.tool-lp-menu').filter('li');
// Remove focus styling from all other menu items.
this.allItems.removeClass('menu-focus');
// Add focus styling to the active item.
this.activeItem.addClass('menu-focus');
// Add focus styling to all parent items.
parentItems.addClass('menu-focus');
// If the bChildOpen flag has been set, open the active item's child menu (if applicable).
if (this.isChildOpen === true) {
var itemUL = item.parent();
// If the itemUL is a root-level menu and item is a parent item,
// show the child menu.
if (itemUL.is('.tool-lp-menu') && (item.attr('aria-haspopup') == 'true')) {
this.openSubMenu(item.children('ul').first());
}
}
return true;
};
/*
* Process blur events for the menu.
*
* @method handleBlur
* @param {Object} item is the jquery object of the item firing the event
* @return boolean Returns false
*/
Menubar.prototype.handleBlur = function(item) {
item.removeClass('menu-focus');
return true;
};
/*
* Determine if the menu should open to the left, or the right,
* based on the screen size and menu position.
* @method setOpenDirection
*/
Menubar.prototype.setOpenDirection = function() {
var pos = this.menuRoot.offset();
var isRTL = $(document.body).hasClass('dir-rtl');
var menuMinWidth = 160;
var openLeft = false;
if (isRTL) {
if (pos.left - menuMinWidth < 0) {
openLeft = true;
}
} else {
if (pos.left + menuMinWidth > $( window ).width()) {
openLeft = true;
}
}
if (openLeft) {
this.menuRoot.addClass('tool-lp-menu-open-left');
} else {
this.menuRoot.removeClass('tool-lp-menu-open-left');
}
};
/*
* Process keyDown events for the menu.
*
* @method handleKeyDown
* @param {Object} item is the jquery object of the item firing the event
* @param {Event} e is the associated event object
* @return boolean Returns false if consuming the event
*/
Menubar.prototype.handleKeyDown = function(item, e) {
if (e.altKey || e.ctrlKey) {
// Modifier key pressed: Do not process.
return true;
}
switch(e.keyCode) {
case this.keys.tab: {
// Hide all menu items and update their aria attributes.
this.menuRoot.find('ul').attr('aria-hidden', 'true');
// Remove focus styling from all menu items.
this.allItems.removeClass('menu-focus');
this.activeItem = null;
this.isChildOpen = false;
break;
}
case this.keys.esc: {
var itemUL = item.parent();
if (itemUL.is('.tool-lp-menu')) {
// Hide the child menu and update the aria attributes.
item.children('ul').first().attr('aria-hidden', 'true');
} else {
// Move up one level.
this.activeItem = itemUL.parent();
// Reset the isChildOpen flag.
this.isChildOpen = false;
// Set focus on the new item.
this.activeItem.focus();
// Hide the active menu and update the aria attributes.
itemUL.attr('aria-hidden', 'true');
}
e.stopPropagation();
return false;
}
case this.keys.enter:
case this.keys.space: {
var parentUL = item.parent();
if (parentUL.is('.tool-lp-menu')) {
// Open the child menu if it is closed.
this.openSubMenu(item.children('ul').first());
} else {
// Remove hover and focus styling.
this.allItems.removeClass('menu-hover');
this.allItems.removeClass('menu-focus');
// Close the menu.
this.menuRoot.find('ul').not('.tool-lp-menu').attr('aria-hidden','true');
// Clear the active item.
this.activeItem = null;
// Call the handler.
// Follow any link, or call the click handlers.
var anchor = item.find('a').first();
var clickEvent = new $.Event('click');
clickEvent.target = anchor;
var eventHandled = false;
if (this.handlers) {
$.each(this.handlers, function(selector, handler) {
if (eventHandled) {
return false;
}
if (item.find(selector).length > 0) {
var callable = $.proxy(handler, anchor);
// False means stop propogatting events.
eventHandled = (callable(clickEvent) === false) || clickEvent.isDefaultPrevented();
}
});
}
if (!eventHandled) {
window.location.href = anchor.attr('href');
}
return true;
}
e.stopPropagation();
return false;
}
case this.keys.left: {
this.activeItem = this.moveToPrevious(item);
this.activeItem.focus();
e.stopPropagation();
return false;
}
case this.keys.right: {
this.activeItem = this.moveToNext(item);
this.activeItem.focus();
e.stopPropagation();
return false;
}
case this.keys.up: {
this.activeItem = this.moveUp(item);
this.activeItem.focus();
e.stopPropagation();
return false;
}
case this.keys.down: {
this.activeItem = this.moveDown(item);
this.activeItem.focus();
e.stopPropagation();
return false;
}
}
return true;
};
/**
* Move to the next menu level.
* This will be either the next root-level menu or the child of a menu parent. If
* at the root level and the active item is the last in the menu, this function will loop
* to the first menu item.
*
* If the menu is a horizontal menu, the first child element of the newly selected menu will
* be selected
*
* @method moveToNext
* @param {Object} item is the active menu item
* @return {Object} Returns the item to move to. Returns item is no move is possible
*/
Menubar.prototype.moveToNext = function(item) {
// Item's containing menu.
var itemUL = item.parent();
// The items in the currently active menu.
var menuItems = itemUL.children('li');
// The number of items in the active menu.
var menuNum = menuItems.length;
// The items index in its menu.
var menuIndex = menuItems.index(item);
var newItem = null;
var childMenu = null;
if (itemUL.is('.tool-lp-menu')) {
// This is the root level move to next sibling. This will require closing
// the current child menu and opening the new one.
if (menuIndex < menuNum-1) {
// Not the last root menu.
newItem = item.next();
} else { // Wrap to first item.
newItem = menuItems.first();
}
// Close the current child menu (if applicable).
if (item.attr('aria-haspopup') == 'true') {
childMenu = item.children('ul').first();
if (childMenu.attr('aria-hidden') == 'false') {
// Update the child menu's aria-hidden attribute.
childMenu.attr('aria-hidden', 'true');
this.isChildOpen = true;
}
}
// Remove the focus styling from the current menu.
item.removeClass('menu-focus');
// Open the new child menu (if applicable).
if ((newItem.attr('aria-haspopup') === 'true') && (this.isChildOpen === true)) {
childMenu = newItem.children('ul').first();
// Update the child's aria-hidden attribute.
this.openSubMenu(childMenu);
}
} else {
// This is not the root level. If there is a child menu to be moved into, do that;
// otherwise, move to the next root-level menu if there is one.
if (item.attr('aria-haspopup') == 'true') {
childMenu = item.children('ul').first();
newItem = childMenu.children('li').first();
// Show the child menu and update its aria attributes.
this.openSubMenu(childMenu);
} else {
// At deepest level, move to the next root-level menu.
var parentMenus = null;
var rootItem = null;
// Get list of all parent menus for item, up to the root level.
parentMenus = item.parentsUntil('ul.tool-lp-menu').filter('ul').not('.tool-lp-menu');
// Hide the current menu and update its aria attributes accordingly.
parentMenus.attr('aria-hidden', 'true');
// Remove the focus styling from the active menu.
parentMenus.find('li').removeClass('menu-focus');
parentMenus.last().parent().removeClass('menu-focus');
// The containing root for the menu.
rootItem = parentMenus.last().parent();
menuIndex = this.rootMenus.index(rootItem);
// If this is not the last root menu item, move to the next one.
if (menuIndex < this.rootMenus.length-1) {
newItem = rootItem.next();
} else {
// Loop.
newItem = this.rootMenus.first();
}
// Add the focus styling to the new menu.
newItem.addClass('menu-focus');
if (newItem.attr('aria-haspopup') == 'true') {
childMenu = newItem.children('ul').first();
newItem = childMenu.children('li').first();
// Show the child menu and update it's aria attributes.
this.openSubMenu(childMenu);
this.isChildOpen = true;
}
}
}
return newItem;
};
/**
* Member function to move to the previous menu level.
* This will be either the previous root-level menu or the child of a menu parent. If
* at the root level and the active item is the first in the menu, this function will loop
* to the last menu item.
*
* If the menu is a horizontal menu, the first child element of the newly selected menu will
* be selected
*
* @method moveToPrevious
* @param {Object} item is the active menu item
* @return {Object} Returns the item to move to. Returns item is no move is possible
*/
Menubar.prototype.moveToPrevious = function(item) {
// Item's containing menu.
var itemUL = item.parent();
// The items in the currently active menu.
var menuItems = itemUL.children('li');
// The items index in its menu.
var menuIndex = menuItems.index(item);
var newItem = null;
var childMenu = null;
if (itemUL.is('.tool-lp-menu')) {
// This is the root level move to previous sibling. This will require closing
// the current child menu and opening the new one.
if (menuIndex > 0) {
// Not the first root menu.
newItem = item.prev();
} else {
// Wrap to last item.
newItem = menuItems.last();
}
// Close the current child menu (if applicable).
if (item.attr('aria-haspopup') == 'true') {
childMenu = item.children('ul').first();
if (childMenu.attr('aria-hidden') == 'false') {
// Update the child menu's aria-hidden attribute.
childMenu.attr('aria-hidden', 'true');
this.isChildOpen = true;
}
}
// Remove the focus styling from the current menu.
item.removeClass('menu-focus');
// Open the new child menu (if applicable).
if ((newItem.attr('aria-haspopup') === 'true') && (this.isChildOpen === true)) {
childMenu = newItem.children('ul').first();
// Update the child's aria-hidden attribute.
this.openSubMenu(childMenu);
}
} else {
// This is not the root level. If there is a parent menu that is not the
// root menu, move up one level; otherwise, move to first item of the previous
// root menu.
var parentLI = itemUL.parent();
var parentUL = parentLI.parent();
// If this is a vertical menu or is not the first child menu
// of the root-level menu, move up one level.
if (!parentUL.is('.tool-lp-menu')) {
newItem = itemUL.parent();
// Hide the active menu and update aria-hidden.
itemUL.attr('aria-hidden', 'true');
// Remove the focus highlight from the item.
item.removeClass('menu-focus');
} else {
// Move to previous root-level menu.
// Hide the current menu and update the aria attributes accordingly.
itemUL.attr('aria-hidden', 'true');
// Remove the focus styling from the active menu.
item.removeClass('menu-focus');
parentLI.removeClass('menu-focus');
menuIndex = this.rootMenus.index(parentLI);
if (menuIndex > 0) {
// Move to the previous root-level menu.
newItem = parentLI.prev();
} else {
// Loop to last root-level menu.
newItem = this.rootMenus.last();
}
// Add the focus styling to the new menu.
newItem.addClass('menu-focus');
if (newItem.attr('aria-haspopup') == 'true') {
childMenu = newItem.children('ul').first();
// Show the child menu and update it's aria attributes.
this.openSubMenu(childMenu);
this.isChildOpen = true;
newItem = childMenu.children('li').first();
}
}
}
return newItem;
};
/**
* Member function to select the next item in a menu.
* If the active item is the last in the menu, this function will loop to the
* first menu item.
*
* @method moveDown
* @param {Object} item is the active menu item
* @param {String} startChr is the character to attempt to match against the beginning of the
* menu item titles. If found, focus moves to the next menu item beginning with that character.
* @return {Object} Returns the item to move to. Returns item is no move is possible
*/
Menubar.prototype.moveDown = function(item, startChr) {
// Item's containing menu.
var itemUL = item.parent();
// The items in the currently active menu.
var menuItems = itemUL.children('li').not('.separator');
// The number of items in the active menu.
var menuNum = menuItems.length;
// The items index in its menu.
var menuIndex = menuItems.index(item);
var newItem = null;
var newItemUL = null;
if (itemUL.is('.tool-lp-menu')) {
// This is the root level menu.
if (item.attr('aria-haspopup') != 'true') {
// No child menu to move to.
return item;
}
// Move to the first item in the child menu.
newItemUL = item.children('ul').first();
newItem = newItemUL.children('li').first();
// Make sure the child menu is visible.
this.openSubMenu(newItemUL);
return newItem;
}
// If $item is not the last item in its menu, move to the next item. If startChr is specified, move
// to the next item with a title that begins with that character.
if (startChr) {
var match = false;
var curNdx = menuIndex+1;
// Check if the active item was the last one on the list.
if (curNdx == menuNum) {
curNdx = 0;
}
// Iterate through the menu items (starting from the current item and wrapping) until a match is found
// or the loop returns to the current menu item.
while (curNdx != menuIndex) {
var titleChr = menuItems.eq(curNdx).html().charAt(0);
if (titleChr.toLowerCase() == startChr) {
match = true;
break;
}
curNdx = curNdx+1;
if (curNdx == menuNum) {
// Reached the end of the list, start again at the beginning.
curNdx = 0;
}
}
if (match === true) {
newItem = menuItems.eq(curNdx);
// Remove the focus styling from the current item.
item.removeClass('menu-focus');
return newItem;
} else {
return item;
}
} else {
if (menuIndex < menuNum-1) {
newItem = menuItems.eq(menuIndex+1);
} else {
newItem = menuItems.first();
}
}
// Remove the focus styling from the current item.
item.removeClass('menu-focus');
return newItem;
};
/**
* Function moveUp() is a member function to select the previous item in a menu.
* If the active item is the first in the menu, this function will loop to the
* last menu item.
*
* @method moveUp
* @param {Object} item is the active menu item
* @return {Object} Returns the item to move to. Returns item is no move is possible
*/
Menubar.prototype.moveUp = function(item) {
// Item's containing menu.
var itemUL = item.parent();
// The items in the currently active menu.
var menuItems = itemUL.children('li').not('.separator');
// The items index in its menu.
var menuIndex = menuItems.index(item);
var newItem = null;
if (itemUL.is('.tool-lp-menu')) {
// This is the root level menu.
// Nothing to do.
return item;
}
// If item is not the first item in its menu, move to the previous item.
if (menuIndex > 0) {
newItem = menuItems.eq(menuIndex-1);
} else {
// Loop to top of menu.
newItem = menuItems.last();
}
// Remove the focus styling from the current item.
item.removeClass('menu-focus');
return newItem;
};
/**
* Enhance the dom with aria attributes.
* @method addAriaAttributes
*/
Menubar.prototype.addAriaAttributes = function() {
this.menuRoot.attr('role', 'menubar');
this.rootMenus.attr('role', 'menuitem');
this.rootMenus.attr('tabindex', '0');
this.rootMenus.attr('aria-haspopup', 'true');
this.subMenus.attr('role', 'menu');
this.subMenus.attr('aria-hidden', 'true');
this.subMenuItems.attr('role', 'menuitem');
this.subMenuItems.attr('tabindex', '-1');
// For CSS styling and effects.
this.menuRoot.addClass('tool-lp-menu');
this.allItems.addClass('tool-lp-menu-item');
this.rootMenus.addClass('tool-lp-root-menu');
this.subMenus.addClass('tool-lp-sub-menu');
};
return /** @alias module:tool_lp/menubar */ {
/**
* Create a menu bar object for every node matching the selector.
*
* The expected DOM structure is shown below.
* <ul> <- This is the target of the selector parameter.
* <li> <- This is repeated for each top level menu.
* Text <- This is the text for the top level menu.
* <ul> <- This is a list of the entries in this top level menu.
* <li> <- This is repeated for each menu entry.
* <a href="someurl">Choice 1</a> <- The anchor for the menu.
* </li>
* </ul>
* </li>
* </ul>
*
* @method enhance
* @param {String} selector - The selector for the outer most menu node.
* @param {Function} handler - Javascript handler for when a menu item was chosen. If the
* handler returns true (or does not exist), the
* menu will look for an anchor with a link to follow.
* For example, if the menu entry has a "data-action" attribute
* and we want to call a javascript function when that entry is chosen,
* we could pass a list of handlers like this:
* { "[data-action='add']" : callAddFunction }
*/
enhance: function(selector, handler) {
$(selector).each(function (index, element) {
var menuRoot = $(element);
// Don't enhance the same menu twice.
if (menuRoot.data("menubarEnhanced") !== true) {
(new Menubar(menuRoot, handler));
menuRoot.data("menubarEnhanced", true);
}
});
},
/**
* Handy function to close all open menus anywhere on the page.
* @method closeAll
*/
closeAll: closeAllSubMenus
};
});

View file

@ -84,7 +84,7 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
}]);
requests[0].done(function(plan) {
var strings = str.get_strings([
str.get_strings([
{ key: 'confirm', component: 'tool_lp' },
{ key: 'deleteplan', component: 'tool_lp', param: plan.name },
{ key: 'delete', component: 'tool_lp' },

View file

@ -30,8 +30,9 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
/**
* Callback to replace the dom element with the rendered template.
*
* @param {string} newhtml The new html to insert.
* @param {string} newjs The new js to run.
* @method updatePage
* @param {String} newhtml The new html to insert.
* @param {String} newjs The new js to run.
*/
var updatePage = function(newhtml, newjs) {
$('[data-region="managetemplates"]').replaceWith(newhtml);
@ -41,6 +42,7 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
/**
* Callback to render the page template again and update the page.
*
* @method reloadList
* @param {Object} context The context for the template.
*/
var reloadList = function(context) {
@ -51,6 +53,7 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
/**
* Delete a template and reload the page.
* @method doDelete
*/
var doDelete = function() {
@ -67,6 +70,7 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
/**
* Handler for "Delete learning plan template" actions.
* @method confirmDelete
* @param {Event} e
*/
var confirmDelete = function(e) {
@ -81,7 +85,7 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
}]);
requests[0].done(function(template) {
var strings = str.get_strings([
str.get_strings([
{ key: 'confirm', component: 'tool_lp' },
{ key: 'deletetemplate', component: 'tool_lp', param: template.shortname },
{ key: 'delete', component: 'tool_lp' },
@ -100,19 +104,14 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
};
return {
return /** @alias module:tool_lp/templatedelete */ {
// Public variables and functions.
/**
* Initialise this plugin. Just attaches some event handlers to the delete entries in the menu.
* Expose the event handler for the delete.
* @method deleteHandler
* @param {Event} e
*/
init: function() {
// Init this module.
$('[data-region="managetemplates"]').on(
"click",
'[data-action="deletetemplate"]',
confirmDelete
);
}
deleteHandler: confirmDelete
};
});

View file

@ -21,17 +21,18 @@
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['core/dragdrop-reorder',
define(['jquery',
'core/str',
'core/notification',
'jquery',
'core/ajax'],
function(dragdrop, str, notification, $, ajax) {
'core/ajax',
'tool_lp/dragdrop-reorder'],
function($, str, notification, ajax, dragdrop) {
// Private variables and functions.
/**
* Handle a drop on a node.
*
* @method handleDrop
* @param {DOMNode} drag
* @param {DOMNode} drop
*/
@ -47,10 +48,11 @@ define(['core/dragdrop-reorder',
};
return {
return /** @alias module:tool_lp/templatemove */ {
// Public variables and functions.
/**
* Initialise this plugin. It loads some strings, then adds the drag/drop functions.
* @method init
*/
init: function() {
// Init this module.

View file

@ -0,0 +1,460 @@
// 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/>.
/**
* Implement an accessible aria tree widget, from a nested unordered list.
* Based on http://oaa-accessibility.org/example/41/
*
* @module tool_lp/tree
* @package core
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/url'], function($, url) {
// Private variables and functions.
/** @var {String} expandedImage The html for an expanded tree node twistie. */
var expandedImage = $('<img alt="" src="' + url.imageUrl('t/expanded') + '"/>');
/** @var {String} collapsedImage The html for a collapsed tree node twistie. */
var collapsedImage = $('<img alt="" src="' + url.imageUrl('t/collapsed') + '"/>');
/**
* Constructor
*
* @param {String} selector
* @param {function} selectCallback Called when the active node is changed.
*/
var Tree = function(selector, selectCallback) {
this.treeRoot = $(selector);
this.items = this.treeRoot.find('li');
this.parents = this.treeRoot.find('li:has(ul)');
this.visibleItems = null;
this.activeItem = null;
this.selectCallback = selectCallback;
this.keys = {
tab: 9,
enter: 13,
space: 32,
pageup: 33,
pagedown: 34,
end: 35,
home: 36,
left: 37,
up: 38,
right: 39,
down: 40,
asterisk: 106
};
this.init();
this.bindEventHandlers();
};
// Public variables and functions.
/**
* Init this tree
* @method init
*/
Tree.prototype.init = function() {
this.parents.attr('aria-expanded', 'true');
this.parents.prepend(expandedImage.clone());
this.items.attr('role', 'tree-item');
this.items.attr('tabindex', '-1');
this.parents.attr('role', 'group');
this.treeRoot.attr('role', 'tree');
this.visibleItems = this.treeRoot.find('li');
};
/**
* Expand a collapsed group.
*
* @method expandGroup
* @param {Object} item is the jquery id of the parent item of the group
*/
Tree.prototype.expandGroup = function(item) {
// Find the first child ul node.
var group = item.children('ul');
// Expand the group.
group.show().attr('aria-hidden', 'false');
item.attr('aria-expanded', 'true');
item.children('img').attr('src', expandedImage.attr('src'));
// Update the list of visible items.
this.visibleItems = this.treeRoot.find('li:visible');
};
/**
* Collapse an expanded group.
*
* @method collapseGroup
* @param {Object} item is the jquery id of the parent item of the group
*/
Tree.prototype.collapseGroup = function(item) {
var group = item.children('ul');
// Collapse the group.
group.hide().attr('aria-hidden', 'true');
item.attr('aria-expanded', 'false');
item.children('img').attr('src', collapsedImage.attr('src'));
// Update the list of visible items.
this.visibleItems = this.treeRoot.find('li:visible');
};
/**
* Expand or collapse a group.
*
* @method toggleGroup
* @param {Object} item is the jquery id of the parent item of the group
*/
Tree.prototype.toggleGroup = function(item) {
if (item.attr('aria-expanded') == 'true') {
this.collapseGroup(item);
} else {
this.expandGroup(item);
}
};
/**
* Set the focus to this item.
*
* @method updateFocus
* @param {Object} item is the jquery id of the parent item of the group
*/
Tree.prototype.updateFocus = function(item) {
this.items.attr('aria-selected', 'false').attr('tabindex', '-1');
item.attr('aria-selected', 'true').attr('tabindex', 0);
this.selectCallback(item);
};
/**
* Handle a key down event - ie navigate the tree.
*
* @method handleKeyDown
* @param {Object} item is the jquery id of the parent item of the group
* @param {Event} e The event.
*/
Tree.prototype.handleKeyDown = function(item, e) {
var currentIndex = this.visibleItems.index(item);
if ((e.altKey || e.ctrlKey) || (e.shiftKey && e.keyCode != this.keys.tab)) {
// Do nothing.
return true;
}
switch (e.keyCode) {
case this.keys.home: {
// Jump to first item in tree.
this.activeItem = this.parents.first();
this.activeItem.focus();
e.stopPropagation();
return false;
}
case this.keys.end: {
// Jump to last visible item.
this.activeItem = this.visibleItems.last();
this.activeItem.focus();
e.stopPropagation();
return false;
}
case this.keys.enter:
case this.keys.space: {
if (item.has('ul')) {
this.toggleGroup(item, true);
}
e.stopPropagation();
return false;
}
case this.keys.left: {
if (item.has('ul') && item.attr('aria-expanded') == 'true') {
this.collapseGroup(item);
} else {
// Move up to the parent.
var itemUL = item.parent();
var itemParent = itemUL.parent();
this.activeItem = itemParent;
this.activeItem.focus();
}
e.stopPropagation();
return false;
}
case this.keys.right: {
if (item.has('ul') && item.attr('aria-expanded') == 'false') {
this.expandGroup(item);
} else {
// Move to the first item in the child group.
this.activeItem = item.children('ul').children('li').first();
this.activeItem.focus();
}
e.stopPropagation();
return false;
}
case this.keys.up: {
if (currentIndex > 0) {
var prev = this.visibleItems.eq(currentIndex - 1);
this.activeItem = prev;
prev.focus();
}
e.stopPropagation();
return false;
}
case this.keys.down: {
if (currentIndex < this.visibleItems.length - 1) {
var next = this.visibleItems.eq(currentIndex + 1);
this.activeItem = next;
next.focus();
}
e.stopPropagation();
return false;
}
case this.keys.asterisk: {
// Expand all groups.
var thisObj = this;
this.parents.each(function() {
thisObj.expandGroup($(this));
});
e.stopPropagation();
return false;
}
}
return true;
};
/**
* Handle a key press event - ie navigate the tree.
*
* @method handleKeyPress
* @param {Object} item is the jquery id of the parent item of the group
* @param {Event} e The event.
*/
Tree.prototype.handleKeyPress = function(item, e) {
if (e.altKey || e.ctrlKey || e.shiftKey) {
// Do nothing.
return true;
}
switch (e.keyCode) {
case this.keys.tab: {
return true;
}
case this.keys.enter:
case this.keys.home:
case this.keys.end:
case this.keys.left:
case this.keys.right:
case this.keys.up:
case this.keys.down: {
e.stopPropagation();
return false;
}
default : {
var chr = String.fromCharCode(e.which);
var match = false;
var itemIndex = this.visibleItems.index(item);
var itemCount = this.visibleItems.length;
var currentIndex = itemIndex + 1;
// Check if the active item was the last one on the list.
if (currentIndex == itemCount) {
currentIndex = 0;
}
// Iterate through the menu items (starting from the current item and wrapping) until a match is found
// or the loop returns to the current menu item.
while (currentIndex != itemIndex) {
var currentItem = this.visibleItems.eq(currentIndex);
var titleChr = currentItem.text().charAt(0);
if (currentItem.has('ul')) {
titleChr = currentItem.find('span').text().charAt(0);
}
if (titleChr.toLowerCase() == chr) {
match = true;
break;
}
currentIndex = currentIndex+1;
if (currentIndex == itemCount) {
// Reached the end of the list, start again at the beginning.
currentIndex = 0;
}
}
if (match === true) {
this.activeItem = this.visibleItems.eq(currentIndex);
this.activeItem.focus();
}
e.stopPropagation();
return false;
}
}
return true;
};
/**
* Handle a double click (expand/collapse).
*
* @method handleDblClick
* @param {Object} item is the jquery id of the parent item of the group
* @param {Event} e The event.
*/
Tree.prototype.handleDblClick = function(item, e) {
if (e.altKey || e.ctrlKey || e.shiftKey) {
// Do nothing.
return true;
}
// Update the active item.
this.activeItem = item;
// Apply the focus markup.
this.updateFocus(item);
// Expand or collapse the group.
this.toggleGroup(item);
e.stopPropagation();
return false;
};
/**
* Handle a click (select).
*
* @method handleClick
* @param {Object} item is the jquery id of the parent item of the group
* @param {Event} e The event.
*/
Tree.prototype.handleClick = function(item, e) {
if (e.altKey || e.ctrlKey || e.shiftKey) {
// Do nothing.
return true;
}
// Update the active item.
this.activeItem = item;
this.updateFocus(item);
e.stopPropagation();
return false;
};
/**
* Handle a blur event
*
* @method handleBlur
* @param {Object} item item is the jquery id of the parent item of the group
* @param {Event} e The event.
*/
Tree.prototype.handleBlur = function() {
return true;
};
/**
* Handle a focus event
*
* @method handleFocus
* @param {Object} item item is the jquery id of the parent item of the group
* @param {Event} e The event.
*/
Tree.prototype.handleFocus = function(item) {
if (this.activeItem === null) {
this.activeItem = item;
}
this.updateFocus(this.activeItem);
return true;
};
/**
* Bind the event listeners we require.
*
* @method bindEventHandlers
*/
Tree.prototype.bindEventHandlers = function() {
var thisObj = this;
// Bind a dblclick handler to the parent items.
this.parents.dblclick(function(e) {
return thisObj.handleDblClick($(this), e);
});
// Bind a click handler.
this.items.click(function(e) {
return thisObj.handleClick($(this), e);
});
// Bind a keydown handler.
this.items.keydown(function(e) {
return thisObj.handleKeyDown($(this), e);
});
// Bind a keypress handler.
this.items.keypress(function(e) {
return thisObj.handleKeyPress($(this), e);
});
// Bind a focus handler.
this.items.focus(function(e) {
return thisObj.handleFocus($(this), e);
});
// Bind a blur handler.
this.items.blur(function(e) {
return thisObj.handleBlur($(this), e);
});
};
return /** @alias module:tool_lp/tree */ Tree;
});

View file

@ -1,25 +1,14 @@
.path-admin-tool-learningplan [data-region="managecompetencies"] ul li,
.path-admin-tool-learningplan [data-region="plans"] ul li,
.path-admin-tool-learningplan [data-region="competencymovetree"] ul li,
.path-admin-tool-learningplan [data-region="competencylinktree"] ul li {
.path-admin-tool-lp [data-region="managecompetencies"] ul li,
.path-admin-tool-lp [data-region="plans"] ul li,
.path-admin-tool-lp [data-region="competencymovetree"] ul li,
.path-admin-tool-lp [data-region="competencylinktree"] ul li {
list-style-type: none;
}
.path-admin-tool-learningplan [data-region="managecompetencies"] ul li img,
.path-admin-tool-learningplan [data-region="plans"] ul li img {
margin-left: -20px;
margin-right: 4px;
}
.dir-rtl.path-admin-tool-learningplan [data-region="plans"] ul li img,
.dir-rtl.path-admin-tool-learningplan [data-region="managecompetencies"] ul li img {
margin-right: -20px;
margin-left: 4px;
}
.path-admin-tool-learningplan [data-region="managecompetencies"] ul[data-enhance="tree"],
.path-admin-tool-learningplan [data-region="plans"] ul[data-enhance="tree"],
.path-admin-tool-learningplan [data-region="competencylinktree"] ul[data-enhance="linktree"],
.path-admin-tool-learningplan [data-region="competencymovetree"] ul[data-enhance="movetree"] {
.path-admin-tool-lp [data-region="managecompetencies"] ul[data-enhance="tree"],
.path-admin-tool-lp [data-region="plans"] ul[data-enhance="tree"],
.path-admin-tool-lp [data-region="competencylinktree"] ul[data-enhance="linktree"],
.path-admin-tool-lp [data-region="competencymovetree"] ul[data-enhance="movetree"] {
border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
transition: border linear .2s,box-shadow linear .2s;
@ -29,37 +18,84 @@
margin-left: 10px;
margin-right: 10px;
}
.path-admin-tool-learningplan [data-region="managecompetencies"] ul,
.path-admin-tool-learningplan [data-region="plans"] ul,
.path-admin-tool-learningplan [data-region="competencylinktree"] ul,
.path-admin-tool-learningplan [data-region="competencymovetree"] ul {
.path-admin-tool-lp [data-region="managecompetencies"] ul,
.path-admin-tool-lp [data-region="plans"] ul,
.path-admin-tool-lp [data-region="competencylinktree"] ul,
.path-admin-tool-lp [data-region="competencymovetree"] ul {
cursor: pointer;
}
.path-admin-tool-learningplan [data-region="competencylinktree"] ul [aria-selected="true"],
.path-admin-tool-learningplan [data-region="competencymovetree"] ul [aria-selected="true"],
.path-admin-tool-learningplan [data-region="plans"] ul [aria-selected="true"],
.path-admin-tool-learningplan [data-region="managecompetencies"] ul [aria-selected="true"] {
.path-admin-tool-lp [data-region="competencylinktree"] ul [aria-selected="true"],
.path-admin-tool-lp [data-region="competencymovetree"] ul [aria-selected="true"],
.path-admin-tool-lp [data-region="plans"] ul [aria-selected="true"],
.path-admin-tool-lp [data-region="managecompetencies"] ul [aria-selected="true"] {
background-color: #dfdfdf;
}
.path-admin-tool-learningplan [data-region="filtercompetencies"] input {
.path-admin-tool-lp [data-region="filtercompetencies"] input {
margin-left: 10px;
}
.path-admin-tool-learningplan [data-region="link-buttons"],
.path-admin-tool-learningplan [data-region="move-buttons"] {
.path-admin-tool-lp [data-region="link-buttons"],
.path-admin-tool-lp [data-region="move-buttons"] {
text-align: center;
}
.dir-rtl.path-admin-tool-learningplan [data-region="filtercompetencies"] input {
.dir-rtl.path-admin-tool-lp [data-region="filtercompetencies"] input {
margin-right: 10px;
}
.path-admin-tool-learningplan [data-region="competencyactionsmenu"] {
display: none;
}
.path-admin-tool-learningplan [data-region="competencyactionsmenu"] .moodle-actionmenu[data-enhanced].show .menu {
white-space: nowrap;
}
.path-admin-tool-learningplan .currentdragtarget {
.path-admin-tool-lp .currentdragtarget {
border: 1px dashed;
}
.path-admin-tool-lp .competencyactionsmenu {
display: inline-block;
vertical-align: text-top;
}
/** Styles required for menubar js */
.tool-lp-menu li {
float: left;
display: inline; position: relative;
list-style-type: none;
}
.tool-lp-sub-menu {
position: absolute;
list-style: none;
margin: 0;
top: -10px;
}
.tool-lp-sub-menu li {
float: none;
}
.tool-lp-menu .tool-lp-sub-menu[aria-hidden=false] {
display: block;
}
.tool-lp-menu ul[aria-hidden=true] {
display: none;
}
.tool-lp-menu .caret {
margin: 8px;
}
.tool-lp-menu.tool-lp-menu-open-left .tool-lp-sub-menu {
margin-left: -120px;
}
.dir-rtl .tool-lp-menu.tool-lp-menu-open-left .tool-lp-sub-menu {
margin-left: 0px;
margin-right: -120px;
}
/** This highlighting is copied from bootstrap - but can be overridden by a theme */
.tool-lp-menu .tool-lp-sub-menu .menu-focus a {
color: #fff ;
text-decoration: none;
background-color: #00699e;
background-image: linear-gradient(to bottom,#0070a8,#005f8f);
background-repeat: repeat-x;
}

View file

@ -20,7 +20,7 @@
Classes required for JS:
Data attibutes required for JS:
* data-enhance=tree
* data-enhance=movetree
Context variables required for this template:
* framework -

View file

@ -56,51 +56,54 @@
</p>
{{#canmanage}}
<div data-region="competencyactions">
<div class="btn-group">
<button class="btn" data-action="add" disabled="disabled">{{#pix}}t/add{{/pix}} {{#str}}addcompetency, tool_lp{{/str}}</button>
</div>
<div data-region="competencyactionsmenu">
<ul class="competencyactionsmenu">
<span data-region="competencyactionsmenu">
<ul title="{{#str}}edit{{/str}}" class="competencyactionsmenu">
<li>
<a href="#" data-action="edit">
{{#pix}}t/edit{{/pix}}{{#str}}edit{{/str}}
</a>
</li>
<li>
<a href="#" data-action="move">
{{#pix}}t/move{{/pix}}{{#str}}movetonewparent, tool_lp{{/str}}
</a>
</li>
<li>
<a href="#" data-action="delete">
{{#pix}}t/delete{{/pix}}{{#str}}delete{{/str}}
</a>
</li>
<li>
<a href="#" data-action="moveup">
{{#pix}}t/up{{/pix}}{{#str}}moveup{{/str}}
</a>
</li>
<li>
<a href="#" data-action="movedown">
{{#pix}}t/down{{/pix}}{{#str}}movedown{{/str}}
</a>
</li>
<li>
<a href="#" data-action="linkedcourses">
{{#pix}}t/viewdetails{{/pix}}{{#str}}linkedcourses, tool_lp{{/str}}
</a>
<a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
<ul class="dropdown-menu">
<li>
<a href="#" data-action="edit">
{{#pix}}t/edit{{/pix}} {{#str}}edit{{/str}}
</a>
</li>
<li>
<a href="#" data-action="move">
{{#pix}}t/move{{/pix}} {{#str}}movetonewparent, tool_lp{{/str}}
</a>
</li>
<li>
<a href="#" data-action="delete">
{{#pix}}t/delete{{/pix}} {{#str}}delete{{/str}}
</a>
</li>
<li>
<a href="#" data-action="moveup">
{{#pix}}t/up{{/pix}} {{#str}}moveup{{/str}}
</a>
</li>
<li>
<a href="#" data-action="movedown">
{{#pix}}t/down{{/pix}} {{#str}}movedown{{/str}}
</a>
</li>
<li>
<a href="#" data-action="linkedcourses">
{{#pix}}t/viewdetails{{/pix}} {{#str}}linkedcourses, tool_lp{{/str}}
</a>
</li>
</ul>
</li>
</ul>
</div>
</span>
</div>
</div>
{{/canmanage}}
</div>
</div>
{{#js}}
// Initialise the JS.
require(['core/tree', 'tool_lp/competencytree', 'tool_lp/competencyactions' ], function(ariatree, treeModel, actions) {
require(['tool_lp/tree', 'tool_lp/competencytree', 'tool_lp/competencyactions' ], function(ariatree, treeModel, actions) {
treeModel.init({{framework.id}});

View file

@ -50,20 +50,23 @@
<td>{{competencies_count}}</td>
<td>
{{#canmanage}}
<div style="display: inline-block;">
<ul class="competencyframeworkactions hide">
<ul title="{{#str}}edit{{/str}}" class="competencyframeworkactions">
<li>
<a href="{{pluginbaseurl}}/editcompetencyframework.php?id={{id}}">
{{#pix}}t/edit{{/pix}}{{#str}}editthiscompetencyframework, tool_lp{{/str}}
</a>
</li>
<li>
<a data-action="deletecompetencyframework" data-frameworkid="{{id}}" href="#">
{{#pix}}t/delete{{/pix}}{{#str}}deletethiscompetencyframework, tool_lp{{/str}}
</a>
<a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
<ul class="dropdown-menu">
<li>
<a href="{{pluginbaseurl}}/editcompetencyframework.php?id={{id}}">
{{#pix}}t/edit{{/pix}} {{#str}}editthiscompetencyframework, tool_lp{{/str}}
</a>
</li>
<li>
<a data-action="deletecompetencyframework" data-frameworkid="{{id}}" href="#">
{{#pix}}t/delete{{/pix}} {{#str}}deletethiscompetencyframework, tool_lp{{/str}}
</a>
</li>
</ul>
</li>
</ul>
</div>
{{/canmanage}}
</td>
</tr>
@ -85,14 +88,15 @@
{{#js}}
// Initialise the JS.
require(['tool_lp/frameworkdelete',
'core/menu',
'tool_lp/menubar',
'tool_lp/frameworkmove'],
function(deleteMod, menu, moveMod) {
function(deleteMod, menubar, moveMod) {
deleteMod.init();
moveMod.init();
menu.menu('{{#str}}edit{{/str}}', '.competencyframeworkactions');
menubar.enhance('.competencyframeworkactions', {
"[data-action='deletecompetencyframework']": deleteMod.deleteHandler
});
});
{{/js}}

View file

@ -48,20 +48,23 @@
<td><span class="drag-handlecontainer"></span><span><a href="{{pluginbaseurl}}/templatecompetencies.php?templateid={{id}}">{{shortname}} {{idnumber}}</a></span> {{^visible}}{{#str}}hiddenhint, tool_lp{{/str}}{{/visible}}</td>
<td>
{{#canmanage}}
<div style="display: inline-block;">
<ul class="templateactions hide">
<ul class="templateactions">
<li>
<a href="{{pluginbaseurl}}/edittemplate.php?id={{id}}">
{{#pix}}t/edit{{/pix}}{{#str}}editthistemplate, tool_lp{{/str}}
</a>
</li>
<li>
<a data-action="deletetemplate" data-templateid="{{id}}" href="#">
{{#pix}}t/delete{{/pix}}{{#str}}deletethistemplate, tool_lp{{/str}}
</a>
<a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
<ul class="dropdown-menu">
<li>
<a href="{{pluginbaseurl}}/edittemplate.php?id={{id}}">
{{#pix}}t/edit{{/pix}} {{#str}}editthistemplate, tool_lp{{/str}}
</a>
</li>
<li>
<a data-action="deletetemplate" data-templateid="{{id}}" href="#">
{{#pix}}t/delete{{/pix}} {{#str}}deletethistemplate, tool_lp{{/str}}
</a>
</li>
</ul>
</li>
</ul>
</div>
{{/canmanage}}
</td>
</tr>
@ -83,14 +86,15 @@
{{#js}}
// Initialise the JS.
require(['tool_lp/templatedelete',
'core/menu',
'tool_lp/menubar',
'tool_lp/templatemove'],
function(deleteMod, menu, moveMod) {
function(deleteMod, menubar, moveMod) {
deleteMod.init();
moveMod.init();
menu.menu('{{#str}}edit{{/str}}', '.templateactions');
menubar.enhance('.templateactions', {
'[data-action="deletetemplate"]': deleteMod.deleteHandler
});
});
{{/js}}

View file

@ -1,11 +1,11 @@
YUI.add('moodle-core-dragdrop-reorder', function (Y, NAME) {
YUI.add('moodle-tool_lp-dragdrop-reorder', function (Y, NAME) {
/**
* Simple drag and drop.
*
* Used when we just want a list of things that can be re-ordered by dragging.
*
* @class M.core.dragdrop_reorder
* @class M.tool_lp.dragdrop_reorder
* @constructor
* @extends M.core.dragdrop
*/
@ -58,13 +58,13 @@ Y.extend(DRAGREORDER, M.core.dragdrop, {
}
}, {
NAME: 'core-dragdrop-reorder',
NAME: 'tool_lp-dragdrop-reorder',
ATTRS: {
}
});
M.core = M.core || {};
M.core.dragdrop_reorder = function(params) {
M.tool_lp = M.tool_lp || {};
M.tool_lp.dragdrop_reorder = function(params) {
new DRAGREORDER(params);
};

View file

@ -0,0 +1 @@
YUI.add("moodle-tool_lp-dragdrop-reorder",function(e,t){var n=function(){n.superclass.constructor.apply(this,arguments)},r={EDITINGMOVE:"editing_move",ICONCLASS:"iconsmall"};e.extend(n,M.core.dragdrop,{initializer:function(t){if(e.one("."+t.parentNodeClass).all("."+t.dragHandleInsertClass).size()<=1)return;this.groups=[t.group],this.samenodeclass=t.sameNodeClass,this.parentnodeclass=t.parentNodeClass,this.draghandleinsertclass=t.dragHandleInsertClass,this.draghandle=this.get_drag_handle(t.dragHandleText,r.EDITINGMOVE,r.ICONCLASS,!0),this.samenodelabel=t.sameNodeLabel,this.parentnodelabel=t.parentNodeLabel,this.callback=t.callback;var n=new e.DD.Delegate({container:"."+t.parentNodeClass,nodes:"."+t.sameNodeClass,target:!0,handles:["."+r.EDITINGMOVE],dragConfig:{groups:this.groups}});n.dd.plug(e.Plugin.DDProxy),e.one("."+t.parentNodeClass).all("."+t.dragHandleInsertClass).each(function(e){e.insert(this.draghandle.cloneNode(!0))},this)},drop_hit:function(e){this.callback(e)}},{NAME:"tool_lp-dragdrop-reorder",ATTRS:{}}),M.tool_lp=M.tool_lp||{},M.tool_lp.dragdrop_reorder=function(e){new n(e)}},"@VERSION@",{requires:["moodle-core-dragdrop"]});

View file

@ -1,11 +1,11 @@
YUI.add('moodle-core-dragdrop-reorder', function (Y, NAME) {
YUI.add('moodle-tool_lp-dragdrop-reorder', function (Y, NAME) {
/**
* Simple drag and drop.
*
* Used when we just want a list of things that can be re-ordered by dragging.
*
* @class M.core.dragdrop_reorder
* @class M.tool_lp.dragdrop_reorder
* @constructor
* @extends M.core.dragdrop
*/
@ -58,13 +58,13 @@ Y.extend(DRAGREORDER, M.core.dragdrop, {
}
}, {
NAME: 'core-dragdrop-reorder',
NAME: 'tool_lp-dragdrop-reorder',
ATTRS: {
}
});
M.core = M.core || {};
M.core.dragdrop_reorder = function(params) {
M.tool_lp = M.tool_lp || {};
M.tool_lp.dragdrop_reorder = function(params) {
new DRAGREORDER(params);
};

View file

@ -1,7 +1,7 @@
{
"name": "moodle-core-dragdrop-reorder",
"name": "moodle-tool_lp-dragdrop-reorder",
"builds": {
"moodle-core-dragdrop-reorder": {
"moodle-tool_lp-dragdrop-reorder": {
"jsfiles": [
"dragdropreorder.js"
]

View file

@ -3,7 +3,7 @@
*
* Used when we just want a list of things that can be re-ordered by dragging.
*
* @class M.core.dragdrop_reorder
* @class M.tool_lp.dragdrop_reorder
* @constructor
* @extends M.core.dragdrop
*/
@ -56,12 +56,12 @@ Y.extend(DRAGREORDER, M.core.dragdrop, {
}
}, {
NAME: 'core-dragdrop-reorder',
NAME: 'tool_lp-dragdrop-reorder',
ATTRS: {
}
});
M.core = M.core || {};
M.core.dragdrop_reorder = function(params) {
M.tool_lp = M.tool_lp || {};
M.tool_lp.dragdrop_reorder = function(params) {
new DRAGREORDER(params);
};

View file

@ -1,5 +1,5 @@
{
"moodle-core-dragdrop-reorder": {
"moodle-tool_lp-dragdrop-reorder": {
"requires": [
"moodle-core-dragdrop"
]

View file

@ -1,82 +0,0 @@
// 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/>.
/**
* Wrapper for the YUI M.core.actionmenu class. Allows us to
* use the YUI version in AMD code until it is replaced.
*
* @module core/menu
* @package core
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/templates', 'core/notification', 'core/yui'], function($, templates, notification, Y) {
// Private variables and functions.
/**
* Replace the menu node in the dom by this new HTML
* rendered from a template and then call enhance on it.
*
* @param {string} newHTML
*/
var enhanceMenu = function(newHTML) {
var newMenu = $(newHTML);
// Insert some more aria attrs into the menu entries.
newMenu.find('li a').each(function(index, element) {
$(element).addClass('menu-action');
$(element).attr('role', 'menuitem');
});
$(this).replaceWith(newMenu);
Y.use('moodle-core-actionmenu', function() {
if (M.core.actionmenu.instance === null) {
M.core.actionmenu.init();
} else {
var yuiNode = Y.one(newMenu.get(0));
M.core.actionmenu.newDOMNode(yuiNode.ancestor());
}
});
};
return /** @alias module:core/menu */ {
// Public variables and functions.
/**
* Wrap M.core.actionmenu.
* @param {string} triggerMessage Text for the button to open the menu.
* @param {string} selector CSS selector for a list of links to turn into a menu (can match mulitple menus).
*/
menu: function(triggerMessage, selector) {
// First we need to modify the list(s) to have markup compatible with actionmenu.
$(selector).each(function (index, element) {
var links = [];
$(element).find('li').each(function (index, link) {
links.push($(link).html().trim());
});
var data = {
triggerMessage: triggerMessage,
links: links
};
var enhanceCallback = $.proxy(enhanceMenu, element);
templates.render('core/menu', data)
.done(enhanceCallback)
.fail(notification.exception);
});
}
};
});

View file

@ -70,7 +70,7 @@ define(['core/config'], function(config) {
}
// Fix admin urls.
if (typeof config.admin != "undefined" && config.admin !== 'admin') {
if (config.admin !== 'admin') {
relativePath = relativePath.replace(/^\/admin\//, '/' + config.admin + '/');
}
return config.wwwroot + relativePath;

View file

@ -1,52 +0,0 @@
{{!
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/>.
}}
{{!
Moodle actionmenu template. The purpose of this list is to take a plain
HTML list of links and changing into specific DOM structure expected by
moodle-actionmenu. It is unlikely you will want to customise this template
because the actionmenu code is looking for specific classes, roles and data-attributes.
Classes required for JS:
* moodle-actionmenu
* menubar
* toggle-display
* textmenu
* menu
Data attibutes required for JS:
* data-enhance = moodle-core-actionmenu
* data-rel = menu-content
Context variables required for this template:
* uniqid - A uniq string that changes every time a template is renderer.
* triggerMessage - A message to show in the link that opens the menu.
* links - An array of things to show in the menu. Standard menus put a link with a pix_icon and a short bit of text.
}}
<div class="moodle-actionmenu" data-enhance="moodle-core-actionmenu">
<ul class="menubar" role="menubar">
<li role="presentation">
<a id="{{uniqid}}-action-menu-toggle" class="toggle-display textmenu" role="menuitem" href="#" aria-haspopup="true">{{triggerMessage}}<b class="caret"></b></a>
</li>
</ul>
<ul class="menu" data-rel="menu-content" aria-labelledby="{{uniqid}}-action-menu-toggle" role="menu" aria-hidden="true">
{{#links}}
<li role="presentation">
{{{.}}}
</li>
{{/links}}
</ul>
</div>

View file

@ -1 +0,0 @@
YUI.add("moodle-core-dragdrop-reorder",function(e,t){var n=function(){n.superclass.constructor.apply(this,arguments)},r={EDITINGMOVE:"editing_move",ICONCLASS:"iconsmall"};e.extend(n,M.core.dragdrop,{initializer:function(t){if(e.one("."+t.parentNodeClass).all("."+t.dragHandleInsertClass).size()<=1)return;this.groups=[t.group],this.samenodeclass=t.sameNodeClass,this.parentnodeclass=t.parentNodeClass,this.draghandleinsertclass=t.dragHandleInsertClass,this.draghandle=this.get_drag_handle(t.dragHandleText,r.EDITINGMOVE,r.ICONCLASS,!0),this.samenodelabel=t.sameNodeLabel,this.parentnodelabel=t.parentNodeLabel,this.callback=t.callback;var n=new e.DD.Delegate({container:"."+t.parentNodeClass,nodes:"."+t.sameNodeClass,target:!0,handles:["."+r.EDITINGMOVE],dragConfig:{groups:this.groups}});n.dd.plug(e.Plugin.DDProxy),e.one("."+t.parentNodeClass).all("."+t.dragHandleInsertClass).each(function(e){e.insert(this.draghandle.cloneNode(!0))},this)},drop_hit:function(e){this.callback(e)}},{NAME:"core-dragdrop-reorder",ATTRS:{}}),M.core=M.core||{},M.core.dragdrop_reorder=function(e){new n(e)}},"@VERSION@",{requires:["moodle-core-dragdrop"]});