MDL-51038 competencies: Make the competencies tree handle multi-select

In the places where it makes sense, add shift/control click support to the
competencies tree (and the keyboard equivalent).
This commit is contained in:
Damyon Wiese
2016-04-18 10:58:41 +08:00
committed by Frederic Massart
parent fdaf46adbb
commit ac588bf3de
14 changed files with 291 additions and 122 deletions
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/notification","core/ajax","core/templates","core/str","tool_lp/competencypicker","tool_lp/dragdrop-reorder"],function(a,b,c,d,e,f,g){var h=function(b,c,d){this.itemid=b,this.itemtype=c,this.pageContextId=d,this.pickerInstance=null,a('[data-region="actions"] button').show(),this.registerEvents(),this.registerDragDrop()};return h.prototype.registerDragDrop=function(){var a=this;e.get_string("movecompetency","tool_lp").done(function(b){g.dragdrop("movecompetency",b,{identifier:"movecompetency",component:"tool_lp"},{identifier:"movecompetencyafter",component:"tool_lp"},"drag-samenode","drag-parentnode","drag-handlecontainer",function(b,c){a.handleDrop.call(a,b,c)})}).fail(b.exception)},h.prototype.handleDrop=function(d,e){var f=a(d).data("id"),g=a(e).data("id"),h=this,i=[];if("course"==h.itemtype)i=c.call([{methodname:"tool_lp_reorder_course_competency",args:{courseid:h.itemid,competencyidfrom:f,competencyidto:g}}]);else if("template"==h.itemtype)i=c.call([{methodname:"tool_lp_reorder_template_competency",args:{templateid:h.itemid,competencyidfrom:f,competencyidto:g}}]);else{if("plan"!=h.itemtype)return null;i=c.call([{methodname:"tool_lp_reorder_plan_competency",args:{planid:h.itemid,competencyidfrom:f,competencyidto:g}}])}i[0].fail(b.exception)},h.prototype.pickCompetency=function(){var e,g,h,i=this;i.pickerInstance||(i.pickerInstance=new f(i.pageContextId,void 0,"course"===i.itemtype?"parents":void 0),i.pickerInstance.on("save",function(f,j){var k=j.competencyId;"course"===i.itemtype?(e=[{methodname:"tool_lp_add_competency_to_course",args:{courseid:i.itemid,competencyid:k}},{methodname:"tool_lp_data_for_course_competencies_page",args:{courseid:i.itemid}}],g="tool_lp/course_competencies_page",h="coursecompetenciespage"):"template"===i.itemtype?(e=[{methodname:"tool_lp_add_competency_to_template",args:{templateid:i.itemid,competencyid:k}},{methodname:"tool_lp_data_for_template_competencies_page",args:{templateid:i.itemid,pagecontext:{contextid:i.pageContextId}}}],g="tool_lp/template_competencies_page",h="templatecompetenciespage"):"plan"===i.itemtype&&(e=[{methodname:"tool_lp_add_competency_to_plan",args:{planid:i.itemid,competencyid:k}},{methodname:"tool_lp_data_for_plan_competencies_page",args:{planid:i.itemid}}],g="tool_lp/plan_page",h="plancompetenciespage"),c.call(e)[1].then(function(b){return d.render(g,b).done(function(b,c){a('[data-region="'+h+'"]').replaceWith(b),d.runTemplateJS(c)})},b.exception)})),i.pickerInstance.display()},h.prototype.registerEvents=function(){var e=this;a('[data-region="actions"] button').click(function(a){a.preventDefault(),e.pickCompetency()}),a('[data-action="delete-competency-link"]').click(function(f){var g=[],h="",i="";f.preventDefault();var j=a(f.target).closest("[data-id]").data("id");"course"==e.itemtype?(g=c.call([{methodname:"tool_lp_remove_competency_from_course",args:{courseid:e.itemid,competencyid:j}},{methodname:"tool_lp_data_for_course_competencies_page",args:{courseid:e.itemid}}]),h="tool_lp/course_competencies_page",i="coursecompetenciespage"):"template"==e.itemtype?(g=c.call([{methodname:"tool_lp_remove_competency_from_template",args:{templateid:e.itemid,competencyid:j}},{methodname:"tool_lp_data_for_template_competencies_page",args:{templateid:e.itemid,pagecontext:{contextid:e.pageContextId}}}]),h="tool_lp/template_competencies_page",i="templatecompetenciespage"):"plan"==e.itemtype&&(g=c.call([{methodname:"tool_lp_remove_competency_from_plan",args:{planid:e.itemid,competencyid:j}},{methodname:"tool_lp_data_for_plan_competencies_page",args:{planid:e.itemid}}]),h="tool_lp/plan_page",i="plancompetenciespage"),g[1].done(function(c){d.render(h,c).done(function(b,c){a('[data-region="'+i+'"]').replaceWith(b),d.runTemplateJS(c)}).fail(b.exception)}).fail(b.exception)})},h});
define(["jquery","core/notification","core/ajax","core/templates","core/str","tool_lp/competencypicker","tool_lp/dragdrop-reorder"],function(a,b,c,d,e,f,g){var h=function(b,c,d){this.itemid=b,this.itemtype=c,this.pageContextId=d,this.pickerInstance=null,a('[data-region="actions"] button').show(),this.registerEvents(),this.registerDragDrop()};return h.prototype.registerDragDrop=function(){var a=this;e.get_string("movecompetency","tool_lp").done(function(b){g.dragdrop("movecompetency",b,{identifier:"movecompetency",component:"tool_lp"},{identifier:"movecompetencyafter",component:"tool_lp"},"drag-samenode","drag-parentnode","drag-handlecontainer",function(b,c){a.handleDrop.call(a,b,c)})}).fail(b.exception)},h.prototype.handleDrop=function(d,e){var f=a(d).data("id"),g=a(e).data("id"),h=this,i=[];if("course"==h.itemtype)i=c.call([{methodname:"tool_lp_reorder_course_competency",args:{courseid:h.itemid,competencyidfrom:f,competencyidto:g}}]);else if("template"==h.itemtype)i=c.call([{methodname:"tool_lp_reorder_template_competency",args:{templateid:h.itemid,competencyidfrom:f,competencyidto:g}}]);else{if("plan"!=h.itemtype)return null;i=c.call([{methodname:"tool_lp_reorder_plan_competency",args:{planid:h.itemid,competencyidfrom:f,competencyidto:g}}])}i[0].fail(b.exception)},h.prototype.pickCompetency=function(){var e,g,h,i=this;i.pickerInstance||(i.pickerInstance=new f(i.pageContextId,void 0,"course"===i.itemtype?"parents":void 0),i.pickerInstance.on("save",function(f,j){var k=j.competencyIds;"course"===i.itemtype?(e=[],a.each(k,function(a,b){e.push({methodname:"tool_lp_add_competency_to_course",args:{courseid:i.itemid,competencyid:b}})}),e.push({methodname:"tool_lp_data_for_course_competencies_page",args:{courseid:i.itemid}}),g="tool_lp/course_competencies_page",h="coursecompetenciespage"):"template"===i.itemtype?(e=[],a.each(k,function(a,b){e.push({methodname:"tool_lp_add_competency_to_template",args:{templateid:i.itemid,competencyid:b}})}),e.push({methodname:"tool_lp_data_for_template_competencies_page",args:{templateid:i.itemid,pagecontext:{contextid:i.pageContextId}}}),g="tool_lp/template_competencies_page",h="templatecompetenciespage"):"plan"===i.itemtype&&(e=[],a.each(k,function(a,b){e.push({methodname:"tool_lp_add_competency_to_plan",args:{planid:i.itemid,competencyid:b}})}),e.push({methodname:"tool_lp_data_for_plan_competencies_page",args:{planid:i.itemid}}),g="tool_lp/plan_page",h="plancompetenciespage"),c.call(e)[e.length-1].then(function(b){return d.render(g,b).done(function(b,c){a('[data-region="'+h+'"]').replaceWith(b),d.runTemplateJS(c)})},b.exception)})),i.pickerInstance.display()},h.prototype.registerEvents=function(){var e=this;a('[data-region="actions"] button').click(function(a){a.preventDefault(),e.pickCompetency()}),a('[data-action="delete-competency-link"]').click(function(f){var g=[],h="",i="";f.preventDefault();var j=a(f.target).closest("[data-id]").data("id");"course"==e.itemtype?(g=c.call([{methodname:"tool_lp_remove_competency_from_course",args:{courseid:e.itemid,competencyid:j}},{methodname:"tool_lp_data_for_course_competencies_page",args:{courseid:e.itemid}}]),h="tool_lp/course_competencies_page",i="coursecompetenciespage"):"template"==e.itemtype?(g=c.call([{methodname:"tool_lp_remove_competency_from_template",args:{templateid:e.itemid,competencyid:j}},{methodname:"tool_lp_data_for_template_competencies_page",args:{templateid:e.itemid,pagecontext:{contextid:e.pageContextId}}}]),h="tool_lp/template_competencies_page",i="templatecompetenciespage"):"plan"==e.itemtype&&(g=c.call([{methodname:"tool_lp_remove_competency_from_plan",args:{planid:e.itemid,competencyid:j}},{methodname:"tool_lp_data_for_plan_competencies_page",args:{planid:e.itemid}}]),h="tool_lp/plan_page",i="plancompetenciespage"),g[1].done(function(c){d.render(h,c).done(function(b,c){a('[data-region="'+i+'"]').replaceWith(b),d.runTemplateJS(c)}).fail(b.exception)}).fail(b.exception)})},h});
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/notification","core/ajax","core/templates","tool_lp/dialogue","core/str","tool_lp/tree"],function(a,b,c,d,e,f,g){var h,i=function(b,c,d){h=this,h._eventNode=a("<div></div>"),h._frameworks=[],h._reset(),h._pageContextId=b,h._pageContextIncludes=d||"children",c&&(h._frameworkId=c,h._singleFramework=!0)};return i.prototype._competencies=null,i.prototype._disallowedCompetencyIDs=null,i.prototype._eventNode=null,i.prototype._frameworks=null,i.prototype._frameworkId=null,i.prototype._pageContextId=null,i.prototype._pageContextIncludes=null,i.prototype._popup=null,i.prototype._searchText="",i.prototype._selectedCompetency=null,i.prototype._singleFramework=!1,i.prototype._afterRender=function(){var b=new g(h._find("[data-enhance=linktree]"));b.on("selectionchanged",function(b,c){var d=c.data("id"),e=!0;a.each(h._disallowedCompetencyIDs,function(a,b){return b==d?(e=!1,!1):void 0}),h._selectedCompetency=null,e&&(h._selectedCompetency=d),h._selectedCompetency?h._find('[data-region="competencylinktree"] [data-action="add"]').removeAttr("disabled"):h._find('[data-region="competencylinktree"] [data-action="add"]').attr("disabled","disabled")}),h._singleFramework||h._find('[data-action="chooseframework"]').change(function(b){h._frameworkId=a(b.target).val(),h._loadCompetencies().then(h._refresh)}),h._find('[data-region="filtercompetencies"] button').click(function(b){return b.preventDefault(),a(b.target).attr("disabled","disabled"),h._searchText=h._find('[data-region="filtercompetencies"] input').val()||"",h._refresh().always(function(){a(b.target).removeAttr("disabled")})}),h._find('[data-region="competencylinktree"] [data-action="cancel"]').click(function(a){a.preventDefault(),h.close()}),h._find('[data-region="competencylinktree"] [data-action="add"]').click(function(a){a.preventDefault(),h._selectedCompetency&&(h._trigger("save",{competencyId:h._selectedCompetency}),h.close())})},i.prototype.close=function(){h._popup.close(),h._reset()},i.prototype.display=function(){return h._render().done(function(a){return f.get_string("competencypicker","tool_lp").done(function(b){h._popup=new e(b,a,h._afterRender.bind(h))})}).fail(b.exception)},i.prototype._fetchCompetencies=function(a,d){return c.call([{methodname:"tool_lp_search_competencies",args:{searchtext:d,competencyframeworkid:a}}])[0].done(function(a){function b(a,c){for(var d=0;d<c.length;d++)c[d].parentid==a.id&&(a.haschildren=!0,c[d].children=[],c[d].haschildren=!1,a.children[a.children.length]=c[d],b(c[d],c))}var c,d,e=[];for(c=0;c<a.length;c++)d=a[c],"0"==d.parentid&&(d.children=[],d.haschildren=0,e[e.length]=d,b(d,a));h._competencies=e}).fail(b.exception)},i.prototype._find=function(b){return a(h._popup.getContent()).find(b)},i.prototype._getFramework=function(b){var c;return a.each(h._frameworks,function(a,d){return d.id==b?(c=d,!1):void 0}),c},i.prototype._loadCompetencies=function(){return h._fetchCompetencies(h._frameworkId,h._searchText)},i.prototype._loadFrameworks=function(){var d;return h._frameworks.length>0?a.when():(d=h._singleFramework?c.call([{methodname:"tool_lp_read_competency_framework",args:{id:this._frameworkId}}])[0].then(function(a){return[a]}):c.call([{methodname:"tool_lp_list_competency_frameworks",args:{sort:"shortname",context:{contextid:h._pageContextId},includes:h._pageContextIncludes}}])[0],d.done(function(a){h._frameworks=a}).fail(b.exception))},i.prototype.on=function(a,b){h._eventNode.on(a,b)},i.prototype._preRender=function(){return h._loadFrameworks().then(function(){return!h._frameworkId&&h._frameworks.length>0&&(h._frameworkId=h._frameworks[0].id),h._frameworkId?h._loadCompetencies():(h._frameworks=[],a.when())})},i.prototype._refresh=function(){return h._render().then(function(a){h._find('[data-region="competencylinktree"]').replaceWith(a),h._afterRender()})},i.prototype._render=function(){return h._preRender().then(function(){h._singleFramework||a.each(h._frameworks,function(a,b){b.id==h._frameworkId?b.selected=!0:b.selected=!1});var b={competencies:h._competencies,framework:h._getFramework(h._frameworkId),frameworks:h._frameworks,search:h._searchText,singleFramework:h._singleFramework};return d.render("tool_lp/competency_picker",b)})},i.prototype._reset=function(){h._competencies=[],h._disallowedCompetencyIDs=[],h._popup=null,h._searchText="",h._selectedCompetency=null},i.prototype.setDisallowedCompetencyIDs=function(a){h._disallowedCompetencyIDs=a},i.prototype._trigger=function(a,b){h._eventNode.trigger(a,[b])},i});
define(["jquery","core/notification","core/ajax","core/templates","tool_lp/dialogue","core/str","tool_lp/tree"],function(a,b,c,d,e,f,g){var h,i=function(b,c,d,e){h=this,h._eventNode=a("<div></div>"),h._frameworks=[],h._reset(),h._pageContextId=b,h._pageContextIncludes=d||"children",h._multiSelect="undefined"==typeof e||e===!0,c&&(h._frameworkId=c,h._singleFramework=!0)};return i.prototype._competencies=null,i.prototype._disallowedCompetencyIDs=null,i.prototype._eventNode=null,i.prototype._frameworks=null,i.prototype._frameworkId=null,i.prototype._pageContextId=null,i.prototype._pageContextIncludes=null,i.prototype._popup=null,i.prototype._searchText="",i.prototype._selectedCompetencies=null,i.prototype._singleFramework=!1,i.prototype._multiSelect=!0,i.prototype._afterRender=function(){var b=new g(h._find("[data-enhance=linktree]"),h._multiSelect);b.on("selectionchanged",function(b,c){var d=c.selected;b.preventDefault();var e=[];a.each(d,function(b,c){var d=a(c).data("id"),f=!0;a.each(h._disallowedCompetencyIDs,function(a,b){b==d&&(f=!1)}),f&&e.push(d)}),h._selectedCompetencies=e,h._selectedCompetencies.length?h._find('[data-region="competencylinktree"] [data-action="add"]').removeAttr("disabled"):h._find('[data-region="competencylinktree"] [data-action="add"]').attr("disabled","disabled")}),h._singleFramework||h._find('[data-action="chooseframework"]').change(function(b){h._frameworkId=a(b.target).val(),h._loadCompetencies().then(h._refresh)}),h._find('[data-region="filtercompetencies"] button').click(function(b){return b.preventDefault(),a(b.target).attr("disabled","disabled"),h._searchText=h._find('[data-region="filtercompetencies"] input').val()||"",h._refresh().always(function(){a(b.target).removeAttr("disabled")})}),h._find('[data-region="competencylinktree"] [data-action="cancel"]').click(function(a){a.preventDefault(),h.close()}),h._find('[data-region="competencylinktree"] [data-action="add"]').click(function(a){a.preventDefault(),h._selectedCompetencies.length&&(h._trigger("save",{competencyIds:h._selectedCompetencies}),h.close())});var c=h._selectedCompetencies.slice(0);a.each(c,function(a,c){var d=h._find("[data-id="+c+"]");d.length&&(b.toggleItem(d),b.updateFocus(d))})},i.prototype.close=function(){h._popup.close(),h._reset()},i.prototype.display=function(){return h._render().done(function(a){return f.get_string("competencypicker","tool_lp").done(function(b){h._popup=new e(b,a,h._afterRender.bind(h))})}).fail(b.exception)},i.prototype._fetchCompetencies=function(a,d){return c.call([{methodname:"tool_lp_search_competencies",args:{searchtext:d,competencyframeworkid:a}}])[0].done(function(a){function b(a,c){for(var d=0;d<c.length;d++)c[d].parentid==a.id&&(a.haschildren=!0,c[d].children=[],c[d].haschildren=!1,a.children[a.children.length]=c[d],b(c[d],c))}var c,d,e=[];for(c=0;c<a.length;c++)d=a[c],"0"==d.parentid&&(d.children=[],d.haschildren=0,e[e.length]=d,b(d,a));h._competencies=e}).fail(b.exception)},i.prototype._find=function(b){return a(h._popup.getContent()).find(b)},i.prototype._getFramework=function(b){var c;return a.each(h._frameworks,function(a,d){return d.id==b?(c=d,!1):void 0}),c},i.prototype._loadCompetencies=function(){return h._fetchCompetencies(h._frameworkId,h._searchText)},i.prototype._loadFrameworks=function(){var d;return h._frameworks.length>0?a.when():(d=h._singleFramework?c.call([{methodname:"tool_lp_read_competency_framework",args:{id:this._frameworkId}}])[0].then(function(a){return[a]}):c.call([{methodname:"tool_lp_list_competency_frameworks",args:{sort:"shortname",context:{contextid:h._pageContextId},includes:h._pageContextIncludes}}])[0],d.done(function(a){h._frameworks=a}).fail(b.exception))},i.prototype.on=function(a,b){h._eventNode.on(a,b)},i.prototype._preRender=function(){return h._loadFrameworks().then(function(){return!h._frameworkId&&h._frameworks.length>0&&(h._frameworkId=h._frameworks[0].id),h._frameworkId?h._loadCompetencies():(h._frameworks=[],a.when())})},i.prototype._refresh=function(){return h._render().then(function(a){h._find('[data-region="competencylinktree"]').replaceWith(a),h._afterRender()})},i.prototype._render=function(){return h._preRender().then(function(){h._singleFramework||a.each(h._frameworks,function(a,b){b.id==h._frameworkId?b.selected=!0:b.selected=!1});var b={competencies:h._competencies,framework:h._getFramework(h._frameworkId),frameworks:h._frameworks,search:h._searchText,singleFramework:h._singleFramework};return d.render("tool_lp/competency_picker",b)})},i.prototype._reset=function(){h._competencies=[],h._disallowedCompetencyIDs=[],h._popup=null,h._searchText="",h._selectedCompetencies=[]},i.prototype.setDisallowedCompetencyIDs=function(a){h._disallowedCompetencyIDs=a},i.prototype._trigger=function(a,b){h._eventNode.trigger(a,[b])},i});
+1 -1
View File
@@ -1 +1 @@
define(["core/ajax","core/notification","core/templates","tool_lp/tree","jquery"],function(a,b,c,d,e){var f={},g=0,h="",i="",j="",k=function(a,b){var c=0,d=!1;for(a.haschildren=!1,a.children=[],c=0;c<b.length;c++)d=b[c],d.parentid==a.id&&(a.haschildren=!0,a.children.push(d),k(d,b))},l=function(b){var l=e.Deferred();return c.render("tool_lp/loading",{}).done(function(m,n){c.replaceNodeContents(e(i),m,n);var o=a.call([{methodname:"tool_lp_search_competencies",args:{searchtext:b,competencyframeworkid:g,includerelated:!0}}]);o[0].done(function(a){f=[];var b=0;for(b=0;b<a.length;b++)f[a[b].id]=a[b];var g=[],m=!1;for(b=0;b<a.length;b++)m=a[b],0===parseInt(m.parentid,10)&&(g.push(m),k(m,a));var n={shortname:h,competencies:g};c.render("tool_lp/competencies_tree_root",n).done(function(a,b){c.replaceNodeContents(e(i),e(a).html(),b);var g=new d(i);if(j){var h=e(i).find("[data-id="+j+"]");h.length&&g.updateFocus(h)}l.resolve(f)}).fail(l.reject)}).fail(l.reject)}),l.promise()},m=function(a,b){j=b.attr("data-id")};return{init:function(a,c,d,e){g=a,h=c,i=e,l(d).fail(b.exception),this.on("selectionchanged",m)},on:function(a,b){e(i).on(a,b)},getChildren:function(a){var b=[];return e.each(f,function(c,d){d.parentid==a&&b.push(d)}),b},getCompetencyFrameworkId:function(){return g},getCompetency:function(a){return f[a]},getCompetencyLevel:function(a){var b=this.getCompetency(a),c=b.path.replace(/^\/|\/$/g,"").split("/").length;return c},hasChildren:function(a){return this.getChildren(a).length>0},reloadCompetencies:function(){return l("").fail(b.exception)},listCompetencies:function(){return f}}});
define(["core/ajax","core/notification","core/templates","tool_lp/tree","jquery"],function(a,b,c,d,e){var f={},g=0,h="",i="",j="",k=function(a,b){var c=0,d=!1;for(a.haschildren=!1,a.children=[],c=0;c<b.length;c++)d=b[c],d.parentid==a.id&&(a.haschildren=!0,a.children.push(d),k(d,b))},l=function(b){var l=e.Deferred();return c.render("tool_lp/loading",{}).done(function(m,n){c.replaceNodeContents(e(i),m,n);var o=a.call([{methodname:"tool_lp_search_competencies",args:{searchtext:b,competencyframeworkid:g,includerelated:!0}}]);o[0].done(function(a){f=[];var b=0;for(b=0;b<a.length;b++)f[a[b].id]=a[b];var g=[],m=!1;for(b=0;b<a.length;b++)m=a[b],0===parseInt(m.parentid,10)&&(g.push(m),k(m,a));var n={shortname:h,competencies:g};c.render("tool_lp/competencies_tree_root",n).done(function(a,b){c.replaceNodeContents(e(i),e(a).html(),b);var g=new d(i,!1);if(j){var h=e(i).find("[data-id="+j+"]");h.length&&(g.selectItem(h),g.updateFocus(h))}l.resolve(f)}).fail(l.reject)}).fail(l.reject)}),l.promise()},m=function(a,b){var c=b.selected.first();j=c.attr("data-id")};return{init:function(a,c,d,e){g=a,h=c,i=e,l(d).fail(b.exception),this.on("selectionchanged",m)},on:function(a,b){e(i).on(a,b)},getChildren:function(a){var b=[];return e.each(f,function(c,d){d.parentid==a&&b.push(d)}),b},getCompetencyFrameworkId:function(){return g},getCompetency:function(a){return f[a]},getCompetencyLevel:function(a){var b=this.getCompetency(a),c=b.path.replace(/^\/|\/$/g,"").split("/").length;return c},hasChildren:function(a){return this.getChildren(a).length>0},reloadCompetencies:function(){return l("").fail(b.exception)},listCompetencies:function(){return f}}});
File diff suppressed because one or more lines are too long
+39 -20
View File
@@ -126,39 +126,58 @@ define(['jquery',
if (!self.pickerInstance) {
self.pickerInstance = new Picker(self.pageContextId, undefined, self.itemtype === 'course' ? 'parents' : undefined);
self.pickerInstance.on('save', function(e, data) {
var compId = data.competencyId;
var compIds = data.competencyIds;
if (self.itemtype === "course") {
requests = [
{ methodname: 'tool_lp_add_competency_to_course',
args: { courseid: self.itemid, competencyid: compId } },
{ methodname: 'tool_lp_data_for_course_competencies_page',
args: { courseid: self.itemid } }
];
requests = [];
$.each(compIds, function(index, compId) {
requests.push({
methodname: 'tool_lp_add_competency_to_course',
args: { courseid: self.itemid, competencyid: compId }
});
});
requests.push({
methodname: 'tool_lp_data_for_course_competencies_page',
args: { courseid: self.itemid }
});
pagerender = 'tool_lp/course_competencies_page';
pageregion = 'coursecompetenciespage';
} else if (self.itemtype === "template") {
requests = [
{ methodname: 'tool_lp_add_competency_to_template',
args: { templateid: self.itemid, competencyid: compId }},
{ methodname: 'tool_lp_data_for_template_competencies_page',
args: { templateid: self.itemid, pagecontext: { contextid: self.pageContextId }}}
];
requests = [];
$.each(compIds, function(index, compId) {
requests.push({
methodname: 'tool_lp_add_competency_to_template',
args: { templateid: self.itemid, competencyid: compId }
});
});
requests.push({
methodname: 'tool_lp_data_for_template_competencies_page',
args: { templateid: self.itemid, pagecontext: { contextid: self.pageContextId }}
});
pagerender = 'tool_lp/template_competencies_page';
pageregion = 'templatecompetenciespage';
} else if (self.itemtype === "plan") {
requests = [
{ methodname: 'tool_lp_add_competency_to_plan',
args: { planid: self.itemid, competencyid: compId }},
{ methodname: 'tool_lp_data_for_plan_competencies_page',
args: { planid: self.itemid}}
];
requests = [];
$.each(compIds, function(index, compId) {
requests.push({
methodname: 'tool_lp_add_competency_to_plan',
args: { planid: self.itemid, competencyid: compId }
});
});
requests.push({
methodname: 'tool_lp_data_for_plan_competencies_page',
args: { planid: self.itemid}
});
pagerender = 'tool_lp/plan_page';
pageregion = 'plancompetenciespage';
}
ajax.call(requests)[1].then(function(context) {
ajax.call(requests)[requests.length - 1].then(function(context) {
return templates.render(pagerender, context).done(function(html, js) {
$('[data-region="' + pageregion + '"]').replaceWith(html);
templates.runTemplateJS(js);
+24 -13
View File
@@ -107,8 +107,9 @@ define(['jquery',
* @param {dialogue} popup The tool_lp/dialogue that was created.
*/
var initMovePopup = function(popup) {
var tree = new Ariatree('[data-enhance=movetree]');
tree.on('selectionchanged', function(evt, target) {
var tree = new Ariatree('[data-enhance=movetree]', false);
tree.on('selectionchanged', function(evt, params) {
var target = params.selected.first();
moveTarget = $(target).data('id');
});
@@ -330,16 +331,24 @@ define(['jquery',
if (!pickerInstance) {
pickerInstance = new Picker(pageContextId, relatedTarget.competencyframeworkid);
pickerInstance.on('save', function(e, data) {
var compId = data.competencyId;
var compIds = data.competencyIds;
var promises = ajax.call([
{ methodname: 'tool_lp_add_related_competency',
args: { competencyid: compId, relatedcompetencyid: relatedTarget.id }},
{ methodname: 'tool_lp_data_for_related_competencies_section',
args: { competencyid: relatedTarget.id }}
]);
var calls = [];
$.each(compIds, function(index, value) {
calls.push({
methodname: 'tool_lp_add_related_competency',
args: { competencyid: value, relatedcompetencyid: relatedTarget.id }
});
});
promises[1].then(function(context) {
calls.push( {
methodname: 'tool_lp_data_for_related_competencies_section',
args: { competencyid: relatedTarget.id }
});
var promises = ajax.call(calls);
promises[calls.length - 1].then(function(context) {
return templates.render('tool_lp/related_competencies', context).done(function(html, js) {
$('[data-region="relatedcompetencies"]').replaceWith(html);
templates.runTemplateJS(js);
@@ -617,9 +626,12 @@ define(['jquery',
/**
* Handler when a node in the aria tree is selected.
* @method selectionChanged
* @param {Event} evt The event that triggered the selection change.
* @param {Object} params The parameters for the event. Contains a list of selected nodes.
*/
var selectionChanged = function(evt, node) {
var id = $(node).data('id'),
var selectionChanged = function(evt, params) {
var node = params.selected.first(),
id = $(node).data('id'),
btn = $('[data-region="competencyactions"] [data-action="add"]'),
actionMenu = $('[data-region="competencyactionsmenu"]'),
selectedTitle = $('[data-region="selected-competency"]'),
@@ -714,6 +726,5 @@ define(['jquery',
ruleConfigInstance = new RuleConfig(treeModel, rulesModules);
ruleConfigInstance.on('save', ruleConfigSaveHandler.bind(this));
}
};
});
+40 -19
View File
@@ -36,8 +36,10 @@ define(['jquery',
* Competency picker class.
* @param {Number} pageContextId The page context ID.
* @param {Number|false} singleFramework The ID of the framework when limited to one.
* @param {String} pageContextIncludes One of 'children', 'parents', 'self'.
* @param {Boolean} multiSelect Support multi-select in the tree.
*/
var Picker = function(pageContextId, singleFramework, pageContextIncludes) {
var Picker = function(pageContextId, singleFramework, pageContextIncludes, multiSelect) {
self = this;
self._eventNode = $('<div></div>');
self._frameworks = [];
@@ -45,6 +47,7 @@ define(['jquery',
self._pageContextId = pageContextId;
self._pageContextIncludes = pageContextIncludes || 'children';
self._multiSelect = (typeof multiSelect === 'undefined' || multiSelect === true);
if (singleFramework) {
self._frameworkId = singleFramework;
self._singleFramework = true;
@@ -70,9 +73,11 @@ define(['jquery',
/** @type {String} The string we filter the competencies with. */
Picker.prototype._searchText = '';
/** @type {Object} The competency that was selected. */
Picker.prototype._selectedCompetency = null;
/** @type {Boolean} Whether we can browser frameworks or not. */
Picker.prototype._selectedCompetencies = null;
/** @type {Boolean} Whether we can browse frameworks or not. */
Picker.prototype._singleFramework = false;
/** @type {Boolean} Do we allow multi select? */
Picker.prototype._multiSelect = true;
/**
* Hook to executed after the view is rendered.
@@ -82,26 +87,30 @@ define(['jquery',
Picker.prototype._afterRender = function() {
// Initialise the tree.
var tree = new Tree(self._find('[data-enhance=linktree]'));
var tree = new Tree(self._find('[data-enhance=linktree]'), self._multiSelect);
tree.on('selectionchanged', function(evt, target) {
var compId = target.data('id'),
valid = true;
tree.on('selectionchanged', function(evt, params) {
var selected = params.selected;
evt.preventDefault();
var validIds = [];
$.each(selected, function(index, item) {
var compId = $(item).data('id'),
valid = true;
$.each(self._disallowedCompetencyIDs, function(i, id) {
if (id == compId) {
valid = false;
return false;
$.each(self._disallowedCompetencyIDs, function(i, id) {
if (id == compId) {
valid = false;
}
});
if (valid) {
validIds.push(compId);
}
});
self._selectedCompetency = null;
if (valid) {
self._selectedCompetency = compId;
}
self._selectedCompetencies = validIds;
// TODO Implement disabling of nodes in the tree module somehow.
if (!self._selectedCompetency) {
if (!self._selectedCompetencies.length) {
self._find('[data-region="competencylinktree"] [data-action="add"]').attr('disabled', 'disabled');
} else {
self._find('[data-region="competencylinktree"] [data-action="add"]').removeAttr('disabled');
@@ -135,13 +144,25 @@ define(['jquery',
// Add listener for add.
self._find('[data-region="competencylinktree"] [data-action="add"]').click(function(e) {
e.preventDefault();
if (!self._selectedCompetency) {
if (!self._selectedCompetencies.length) {
return;
}
self._trigger('save', { competencyId: self._selectedCompetency });
self._trigger('save', { competencyIds: self._selectedCompetencies });
self.close();
});
// The list of selected competencies will be modified while looping (because of the listeners above).
var currentItems = self._selectedCompetencies.slice(0);
$.each(currentItems, function(index, id) {
var node = self._find('[data-id=' + id + ']');
if (node.length) {
tree.toggleItem(node);
tree.updateFocus(node);
}
});
};
/**
@@ -380,7 +401,7 @@ define(['jquery',
self._disallowedCompetencyIDs = [];
self._popup = null;
self._searchText = '';
self._selectedCompetency = null;
self._selectedCompetencies = [];
};
/**
+5 -3
View File
@@ -101,11 +101,12 @@ define(['core/ajax', 'core/notification', 'core/templates', 'tool_lp/tree', 'jqu
};
templates.render('tool_lp/competencies_tree_root', context).done(function(html, js) {
templates.replaceNodeContents($(treeSelector), $(html).html(), js);
var tree = new Ariatree(treeSelector);
var tree = new Ariatree(treeSelector, false);
if (currentNodeId) {
var node = $(treeSelector).find('[data-id=' + currentNodeId + ']');
if (node.length) {
tree.selectItem(node);
tree.updateFocus(node);
}
}
@@ -120,9 +121,10 @@ define(['core/ajax', 'core/notification', 'core/templates', 'tool_lp/tree', 'jqu
/**
* Whenever the current item in the tree is changed - remember the "id".
* @param {Event} evt
* @param {Node} The active node in the tree.
* @param {Object} The parameters for the event.
*/
var rememberCurrent = function(evt, node) {
var rememberCurrent = function(evt, params) {
var node = params.selected.first();
currentNodeId = node.attr('data-id');
};
+153 -53
View File
@@ -37,16 +37,25 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
* Constructor
*
* @param {String} selector
* @param {Boolean} multiSelect
*/
var Tree = function(selector) {
var Tree = function(selector, multiSelect) {
this.treeRoot = $(selector);
this.multiSelect = (typeof multiSelect === 'undefined' || multiSelect === true);
this.items = this.treeRoot.find('li');
this.expandAll = this.items.length < 20;
this.parents = this.treeRoot.find('li:has(ul)');
if (multiSelect) {
this.treeRoot.attr('aria-multiselectable', 'true');
}
this.items.attr('aria-selected', 'false');
this.visibleItems = null;
this.activeItem = null;
this.lastActiveItem = null;
this.keys = {
tab: 9,
@@ -148,13 +157,36 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
}
};
/**
* 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) {
Tree.prototype.triggerChange = function() {
var allSelected = this.items.filter('[aria-selected=true]');
this.treeRoot.trigger('selectionchanged', { selected: allSelected });
};
Tree.prototype.multiSelectItem = function(item) {
if (!this.multiSelect) {
this.items.attr('aria-selected', 'false');
} else if (this.lastActiveItem !== null) {
var lastIndex = this.visibleItems.index(this.lastActiveItem);
var currentIndex = this.visibleItems.index(this.activeItem);
var oneItem = null;
while (lastIndex < currentIndex) {
oneItem = $(this.visibleItems.get(lastIndex));
oneItem.attr('aria-selected', 'true');
lastIndex++;
}
while (lastIndex > currentIndex) {
oneItem = $(this.visibleItems.get(lastIndex));
oneItem.attr('aria-selected', 'true');
lastIndex--;
}
}
item.attr('aria-selected', 'true');
this.triggerChange();
};
Tree.prototype.selectItem = function(item) {
// Expand all nodes up the tree.
var walk = item.parent();
while (walk.attr('role') != 'tree') {
@@ -164,9 +196,46 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
}
walk = walk.parent();
}
this.items.attr('aria-selected', 'false').attr('tabindex', '-1');
item.attr('aria-selected', 'true').attr('tabindex', 0);
this.treeRoot.trigger('selectionchanged', [item]);
this.items.attr('aria-selected', 'false');
item.attr('aria-selected', 'true');
this.triggerChange();
};
Tree.prototype.toggleItem = function(item) {
if (!this.multiSelect) {
return this.selectItem(item);
}
var current = item.attr('aria-selected');
if (current === 'true') {
current = 'false';
} else {
current = 'true';
}
item.attr('aria-selected', current);
this.triggerChange();
};
/**
* 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.lastActiveItem = this.activeItem;
this.activeItem = item;
// Expand all nodes up the tree.
var walk = item.parent();
while (walk.attr('role') != 'tree') {
walk = walk.parent();
if (walk.attr('aria-expanded') == 'false') {
this.expandGroup(walk);
}
walk = walk.parent();
}
this.items.attr('tabindex', '-1');
item.attr('tabindex', 0);
};
/**
@@ -178,27 +247,31 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
*/
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;
}
var newItem = null;
switch (e.keyCode) {
case this.keys.home: {
// Jump to first item in tree.
this.activeItem = this.parents.first();
this.activeItem.focus();
newItem = this.parents.first();
newItem.focus();
if (e.shiftKey) {
this.multiSelectItem(newItem);
} else if (!e.ctrlKey) {
this.selectItem(newItem);
}
e.stopPropagation();
return false;
}
case this.keys.end: {
// Jump to last visible item.
this.activeItem = this.visibleItems.last();
this.activeItem.focus();
newItem = this.visibleItems.last();
newItem.focus();
if (e.shiftKey) {
this.multiSelectItem(newItem);
} else if (!e.ctrlKey) {
this.selectItem(newItem);
}
e.stopPropagation();
return false;
@@ -206,8 +279,12 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
case this.keys.enter:
case this.keys.space: {
if (item.has('ul')) {
this.toggleGroup(item, true);
if (e.shiftKey) {
this.multiSelectItem(item);
} else if (e.ctrlKey) {
this.toggleItem(item);
} else {
this.selectItem(item);
}
e.stopPropagation();
@@ -220,10 +297,13 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
// Move up to the parent.
var itemUL = item.parent();
var itemParent = itemUL.parent();
itemParent.focus();
if (e.shiftKey) {
this.multiSelectItem(itemParent);
} else if (!e.ctrlKey) {
this.selectItem(itemParent);
}
this.activeItem = itemParent;
this.activeItem.focus();
}
e.stopPropagation();
@@ -234,9 +314,13 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
this.expandGroup(item);
} else {
// Move to the first item in the child group.
this.activeItem = item.children('ul').children('li').first();
this.activeItem.focus();
newItem = item.children('ul').children('li').first();
newItem.focus();
if (e.shiftKey) {
this.multiSelectItem(newItem);
} else if (!e.ctrlKey) {
this.selectItem(newItem);
}
}
e.stopPropagation();
@@ -246,10 +330,12 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
if (currentIndex > 0) {
var prev = this.visibleItems.eq(currentIndex - 1);
this.activeItem = prev;
prev.focus();
if (e.shiftKey) {
this.multiSelectItem(prev);
} else if (!e.ctrlKey) {
this.selectItem(prev);
}
}
e.stopPropagation();
@@ -259,9 +345,12 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
if (currentIndex < this.visibleItems.length - 1) {
var next = this.visibleItems.eq(currentIndex + 1);
this.activeItem = next;
next.focus();
if (e.shiftKey) {
this.multiSelectItem(next);
} else if (!e.ctrlKey) {
this.selectItem(next);
}
}
e.stopPropagation();
return false;
@@ -346,8 +435,7 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
}
if (match === true) {
this.activeItem = this.visibleItems.eq(currentIndex);
this.activeItem.focus();
this.updateFocus(this.visibleItems.eq(currentIndex));
}
e.stopPropagation();
return false;
@@ -386,9 +474,6 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
return true;
}
// Update the active item.
this.activeItem = item;
// Apply the focus markup.
this.updateFocus(item);
@@ -399,6 +484,22 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
return false;
};
/**
* Handle a click (select).
*
* @method handleExpandCollapseClick
* @param {Object} item is the jquery id of the parent item of the group
* @param {Event} e The event.
*/
Tree.prototype.handleExpandCollapseClick = function(item, e) {
// Do not shift the focus.
this.toggleGroup(item);
e.stopPropagation();
return false;
};
/**
* Handle a click (select).
*
@@ -408,16 +509,14 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
*/
Tree.prototype.handleClick = function(item, e) {
if (e.altKey || e.ctrlKey || e.shiftKey) {
// Do nothing.
return true;
if (e.shiftKey) {
this.multiSelectItem(item);
} else if (e.ctrlKey) {
this.toggleItem(item);
} else {
this.selectItem(item);
}
// Update the active item.
this.activeItem = item;
this.updateFocus(item);
e.stopPropagation();
return false;
};
@@ -442,11 +541,7 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
*/
Tree.prototype.handleFocus = function(item) {
if (this.activeItem === null) {
this.activeItem = item;
}
this.updateFocus(this.activeItem);
this.updateFocus(item);
return true;
};
@@ -469,6 +564,11 @@ define(['jquery', 'core/url', 'core/log'], function($, url, log) {
return thisObj.handleClick($(this), e);
});
// Bind a toggle handler to the expand/collapse icons.
this.items.children('img').click(function(e) {
return thisObj.handleExpandCollapseClick($(this).parent(), e);
});
// Bind a keydown handler.
this.items.keydown(function(e) {
return thisObj.handleKeyDown($(this), e);
+21 -5
View File
@@ -24,12 +24,28 @@
.path-admin-tool-lp [data-region="competencymovetree"] ul {
cursor: pointer;
}
.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"] {
.path-admin-tool-lp [data-region="competencylinktree"] ul li>span,
.path-admin-tool-lp [data-region="competencymovetree"] ul li>span,
.path-admin-tool-lp [data-region="plans"] ul li>span,
.path-admin-tool-lp [data-region="managecompetencies"] ul li>span {
padding-top: 2px;
padding-bottom: 2px;
padding-left: 4px;
padding-right: 4px;
border-radius: 4px;
}
.path-admin-tool-lp [data-region="competencylinktree"] ul [aria-selected="true"]>span,
.path-admin-tool-lp [data-region="competencymovetree"] ul [aria-selected="true"]>span,
.path-admin-tool-lp [data-region="plans"] ul [aria-selected="true"]>span,
.path-admin-tool-lp [data-region="managecompetencies"] ul [aria-selected="true"]>span {
background-color: #dfdfdf;
}
.path-admin-tool-lp [data-region="competencylinktree"] ul [tabindex="0"]>span,
.path-admin-tool-lp [data-region="competencymovetree"] ul [tabindex="0"]>span,
.path-admin-tool-lp [data-region="plans"] ul [tabindex="0"]>span,
.path-admin-tool-lp [data-region="managecompetencies"] ul [tabindex="0"]>span {
border: 2px solid #0070a8;
}
.path-admin-tool-lp [data-region="filtercompetencies"] input {
margin-left: 10px;
}
@@ -145,4 +161,4 @@
input[type="radio"].tool_lp_scale_default,
input[type="checkbox"].tool_lp_scale_proficient {
margin-top: 0px;
}
}
@@ -1,7 +1,7 @@
<li data-id="{{id}}" draggable="true">
{{^visible}}<span class="disabled">{{/visible}}
<span {{^visible}}class="disabled"{{/visible}}>
{{shortname}}
{{^visible}}</span>{{/visible}}
</span>
{{#haschildren}}
<ul>
{{#children}}
@@ -1,5 +1,5 @@
<ul data-enhance="tree">
<li>{{shortname}}
<li><span>{{shortname}}</span>
<ul>
{{#competencies}}
{{> tool_lp/competencies_tree }}
@@ -15,7 +15,7 @@
<button>{{#pix}}a/search, ,{{#str}}search{{/str}}{{/pix}}</button>
</form>
<ul data-enhance="linktree">
<li>{{framework.shortname}}
<li><span>{{framework.shortname}}</span>
<ul>
{{#competencies}}
{{> tool_lp/competencies_tree }}