From 461226ed27b73192f3a48923e9dd9d78f5236e86 Mon Sep 17 00:00:00 2001 From: Ferran Recio Date: Thu, 30 Sep 2021 18:57:17 +0200 Subject: [PATCH] MDL-72569 core_courseformat: aria-tree to move tool --- course/amd/build/actions.min.js | 2 +- course/amd/build/actions.min.js.map | 2 +- course/amd/src/actions.js | 34 +++++ .../amd/build/local/content/actions.min.js | 2 +- .../build/local/content/actions.min.js.map | 2 +- .../local/courseeditor/contenttree.min.js | 2 + .../local/courseeditor/contenttree.min.js.map | 1 + .../local/courseindex/courseindex.min.js | 2 +- .../local/courseindex/courseindex.min.js.map | 2 +- .../local/courseindex/keyboardnav.min.js | 2 - .../local/courseindex/keyboardnav.min.js.map | 1 - .../format/amd/src/local/content/actions.js | 89 ++++++++++++- .../contenttree.js} | 66 ++++++---- .../amd/src/local/courseindex/courseindex.js | 6 +- .../templates/local/content/movecm.mustache | 16 ++- .../local/content/movesection.mustache | 5 +- .../tests/behat/movecm_keyboard.feature | 121 ++++++++++++++++++ .../tests/behat/movesection_keyboard.feature | 65 ++++++++++ lib/amd/build/local/reactive/reactive.min.js | 2 +- .../build/local/reactive/reactive.min.js.map | 2 +- lib/amd/build/tree.min.js | 2 +- lib/amd/build/tree.min.js.map | 2 +- lib/amd/src/local/reactive/reactive.js | 7 + lib/amd/src/tree.js | 2 +- 24 files changed, 385 insertions(+), 52 deletions(-) create mode 100644 course/format/amd/build/local/courseeditor/contenttree.min.js create mode 100644 course/format/amd/build/local/courseeditor/contenttree.min.js.map delete mode 100644 course/format/amd/build/local/courseindex/keyboardnav.min.js delete mode 100644 course/format/amd/build/local/courseindex/keyboardnav.min.js.map rename course/format/amd/src/local/{courseindex/keyboardnav.js => courseeditor/contenttree.js} (64%) create mode 100644 course/format/tests/behat/movecm_keyboard.feature create mode 100644 course/format/tests/behat/movesection_keyboard.feature diff --git a/course/amd/build/actions.min.js b/course/amd/build/actions.min.js index ba34f49aa12..d93722dd68e 100644 --- a/course/amd/build/actions.min.js +++ b/course/amd/build/actions.min.js @@ -1,2 +1,2 @@ -define ("core_course/actions",["jquery","core/ajax","core/templates","core/notification","core/str","core/url","core/yui","core/modal_factory","core/modal_events","core/key_codes","core/log","core_courseformat/courseeditor","core/event_dispatcher","core_course/events"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){var o=["moveSection","moveCm","addSection","deleteSection"],p=l.getCurrentCourseEditor(),q,r={EDITINPROGRESS:"editinprogress",SECTIONDRAGGABLE:"sectiondraggable",EDITINGMOVE:"editing_move"},s={ACTIVITYLI:"li.activity",ACTIONAREA:".actions",ACTIVITYACTION:"a.cm-edit-action",MENU:".moodle-actionmenu[data-enhance=moodle-core-actionmenu]",TOGGLE:".toggle-display,.dropdown-toggle",SECTIONLI:"li.section",SECTIONACTIONMENU:".section_action_menu",ADDSECTIONS:".changenumsections [data-add-sections]"};g.use("moodle-course-coursebase",function(){var a=M.course.format.get_section_selector();if(a){s.SECTIONLI=a}});var t=function(a,b,c,d){if(!(c instanceof Element)&&c.get!==void 0){c=c.get(0)}return m.dispatchEvent(a,b,c,d)},u=function(a){var b=a.get(0);if(b.dataset.id){return b.dataset.id}var c;g.use("moodle-course-util",function(a){c=a.Moodle.core_course.util.cm.getId(a.Node(b))});return c},v=function(a){var b;g.use("moodle-course-util",function(c){b=c.Moodle.core_course.util.cm.getName(c.Node(a.get(0)))});var c=p.state,d=u(a);if(!b&&c&&d){var e;b=null===(e=c.cm.get(d))||void 0===e?void 0:e.name}return b},w=function(a){a.addClass(r.EDITINPROGRESS);var b=a.find(s.ACTIONAREA).get(0);if(b){var c=M.util.add_spinner(g,g.Node(b));c.show();if(a.data("id")!==void 0){p.dispatch("cmLock",[a.data("id")],!0)}return c}return null},x=function(a){a.addClass(r.EDITINPROGRESS);var b=a.find(s.SECTIONACTIONMENU).get(0);if(b){var c=M.util.add_spinner(g,g.Node(b));c.show();if(a.data("id")!==void 0){p.dispatch("sectionLock",[a.data("id")],!0)}return c}return null},y=function(a){var b=M.util.add_lightbox(g,g.Node(a.get(0)));b.show();return b},z=function(a,b,c){window.setTimeout(function(){a.removeClass(r.EDITINPROGRESS);if(b){b.hide()}if(a.data("id")!==void 0){var c="section"===a.data("for")?"sectionLock":"cmLock";p.dispatch(c,[a.data("id")],!1)}},c)},A=function(a,b){if(a){window.setTimeout(function(){a.hide()},b)}},B=function(a){g.use("moodle-course-coursebase",function(){M.course.coursebase.invoke_function("setup_for_resource","#"+a)});if(M.core.actionmenu&&M.core.actionmenu.newDOMNode){M.core.actionmenu.newDOMNode(g.one("#"+a))}},C=function(b,c){var d=a("#"+b),e="[data-action="+c+"]";if("groupsseparate"===c||"groupsvisible"===c||"groupsnone"===c){e="[data-action=groupsseparate],[data-action=groupsvisible],[data-action=groupsnone]"}if(d.find(e).is(":visible")){d.find(e).focus()}else{d.find(s.MENU).find(s.TOGGLE).focus()}},D=function(b){var c=a("a:visible"),d=!1,e=null;c.each(function(){if(a.contains(b[0],this)){d=!0}else if(d){e=this;return!1}return!0});return e},E=function(c,e,f){var g=f.attr("data-action"),h=w(c),i=b.call([{methodname:"core_course_edit_module",args:{id:e,action:g,sectionreturn:f.attr("data-sectionreturn")?f.attr("data-sectionreturn"):0}}],!0),j;if("duplicate"===g){j=y(f.closest(s.SECTIONLI))}a.when.apply(a,i).done(function(b){var d=D(c);c.replaceWith(b);var f=[];a("
"+b+"
").find(s.ACTIVITYLI).each(function(b){B(a(this).attr("id"));if(0===b){C(a(this).attr("id"),g);d=null}f.push(u(a(this)))});if(d){d.focus()}z(c,h,400);A(j,400);c.trigger(a.Event("coursemoduleedited",{ajaxreturn:b,action:g}));p.dispatch("legacyActivityAction",g,e,f)}).fail(function(b){z(c,h);A(j);var f=a.Event("coursemoduleeditfailed",{exception:b,action:g});c.trigger(f);if(!f.isDefaultPrevented()){d.exception(b)}})},F=function(c,d,e){if(e===void 0){e=p.sectionReturn}var f=a(c),g=w(f),h=b.call([{methodname:"core_course_get_module",args:{id:d,sectionreturn:e}}],!0);return new Promise(function(b,c){a.when.apply(a,h).done(function(a){z(f,g,400);K(a);b(a)}).fail(function(){z(f,g);c()})})},G=function(a,b){var c=a.attr("class").match(/modtype_([^\s]*)/)[1],f=v(a);e.get_string("pluginname",c).done(function(a){e.get_strings([{key:"confirm",component:"core"},{key:null===f?"deletechecktype":"deletechecktypename",param:{type:a,name:f}},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],b)})})},H=function(a,b){e.get_strings([{key:"confirm"},{key:"yes"},{key:"no"}]).done(function(c){d.confirm(c[0],a,c[1],c[2],b)})},I=function(a,b,f,g,h){return e.get_strings([{key:f,component:g}]).then(function(d){a.find("span.menu-action-text").html(d[0]);return c.renderPix(b,"core")}).then(function(b){a.find(".icon").replaceWith(b);a.attr("data-action",h)}).catch(d.exception)},J=function(b,c,d,e,f){var g=c.attr("data-action");if("hide"===g||"show"===g){if("hide"===g){b.addClass("hidden");I(c,"i/show","showfromothers","format_"+e,"show")}else{b.removeClass("hidden");I(c,"i/hide","hidefromothers","format_"+e,"hide")}if(d.modules!==void 0){for(var h in d.modules){K(d.modules[h])}}if(d.section_availability!==void 0){b.find(".section_availability").first().replaceWith(d.section_availability)}var k=p.state.section.get(f);if(k!==void 0){p.dispatch("sectionState",[f])}}else if("setmarker"===g){var i=a(s.SECTIONLI+".current"),j=i.find(s.SECTIONACTIONMENU+" a[data-action=removemarker]");i.removeClass("current");I(j,"i/marker","highlight","core","setmarker");b.addClass("current");I(c,"i/marked","highlightoff","core","removemarker");p.dispatch("legacySectionAction",g,f)}else if("removemarker"===g){b.removeClass("current");I(c,"i/marker","highlight","core","setmarker");p.dispatch("legacySectionAction",g,f)}},K=function(b){a("
"+b+"
").find(s.ACTIVITYLI).each(function(){var c=a(this).attr("id");a(s.ACTIVITYLI+"#"+c).replaceWith(b);B(c)})},L=function(c,e,f,g){var h=f.attr("data-action"),i=f.attr("data-sectionreturn")?f.attr("data-sectionreturn"):0;if(p.supportComponents&&o.includes(h)){return!1}var j=x(c),k=b.call([{methodname:"core_course_edit_section",args:{id:e,action:h,sectionreturn:i}}],!0),l=y(c);a.when.apply(a,k).done(function(b){var d=a.parseJSON(b);z(c,j);A(l);c.find(s.SECTIONACTIONMENU).find(s.TOGGLE).focus();var i=a.Event("coursesectionedited",{ajaxreturn:d,action:h});c.trigger(i);if(!i.isDefaultPrevented()){J(c,f,d,g,e)}}).fail(function(b){z(c,j);A(l);var f=a.Event("coursesectioneditfailed",{exception:b,action:h});c.trigger(f);if(!f.isDefaultPrevented()){d.exception(b)}});return!0};g.use("moodle-course-coursebase",function(){M.course.coursebase.register_module({set_visibility_resource_ui:function set_visibility_resource_ui(b){var c=a(b.element.getDOMNode()),d=u(c);if(d){var e=c.find("."+r.EDITINGMOVE).attr("data-sectionreturn");F(c,d,e)}},updateMovedCmState:function updateMovedCmState(a){var b=p.state,c=b.cm.get(a.cmid);if(c!==void 0){p.dispatch("sectionState",[c.sectionid])}p.dispatch("cmState",[a.cmid])},updateMovedSectionState:function updateMovedSectionState(){p.dispatch("courseState")}})});p.addMutations({legacyActivityAction:function legacyActivityAction(a,b,c,d){var e=a.state,f=e.cm.get(c);if(f===void 0){return}var g=e.section.get(f.sectionid);if(g===void 0){return}a.setReadOnly(!1);f.locked=!0;a.setReadOnly(!0);a.setReadOnly(!1);f.locked=!1;switch(b){case"delete":g.cmlist=g.cmlist.reduce(function(a,b){if(b!=c){a.push(b)}return a},[]);e.cm.delete(c);break;case"hide":case"show":f.visible="show"===b?!0:!1;break;case"duplicate":p.dispatch("cmState",d);break;}a.setReadOnly(!0)},legacySectionAction:function legacySectionAction(a,b,c){var d=a.state,e=d.section.get(c);if(e===void 0){return}a.setReadOnly(!1);e.locked=!0;a.setReadOnly(!0);a.setReadOnly(!1);e.locked=!1;switch(b){case"setmarker":d.section.forEach(function(a){if(a.id!=c){a.current=!1}});e.current=!0;break;case"removemarker":e.current=!1;break;}a.setReadOnly(!0)}});return{initCoursePage:function initCoursePage(b){q=b;a("body").on("click keypress",s.ACTIVITYLI+" "+s.ACTIVITYACTION+"[data-action]",function(b){if("keypress"===b.type&&13!==b.keyCode){return}var c=a(this),d=c.closest(s.ACTIVITYLI),e=c.attr("data-action"),f=u(d);switch(e){case"moveleft":case"moveright":case"delete":case"duplicate":case"hide":case"stealth":case"show":case"groupsseparate":case"groupsvisible":case"groupsnone":break;default:return;}if(!f){return}b.preventDefault();if("delete"===e){G(d,function(){E(d,f,c)})}else{E(d,f,c)}});a("body").on("click keypress",s.SECTIONLI+" "+s.SECTIONACTIONMENU+"[data-sectionid] a[data-action]",function(c){if("keypress"===c.type&&13!==c.keyCode){return}var d=a(this),e=d.closest(s.SECTIONLI),f=d.closest(s.SECTIONACTIONMENU).attr("data-sectionid"),g=!0;if(d.attr("data-confirm")){H(d.attr("data-confirm"),function(){g=L(e,f,d,b)})}else{g=L(e,f,d,b)}if(g){c.preventDefault()}});a("body").on("updated","".concat(s.SECTIONLI," [data-inplaceeditable]"),function(a){if(a.ajaxreturn&&a.ajaxreturn.itemid){var b=p.state,c=b.section.get(a.ajaxreturn.itemid);if(c!==void 0){p.dispatch("sectionState",[a.ajaxreturn.itemid])}}});a("body").on("updated","".concat(s.ACTIVITYLI," [data-inplaceeditable]"),function(a){if(a.ajaxreturn&&a.ajaxreturn.itemid){p.dispatch("cmState",[a.ajaxreturn.itemid])}});if(p.supportComponents&&o.includes("addSection")){return}e.get_string("numberweeks").done(function(b){var c=a(s.ADDSECTIONS),d=c.attr("data-add-sections"),e=c.attr("data-new-sections"),f=a("
");f.find("label").html(b);h.create({title:d,type:h.types.SAVE_CANCEL,body:f.html()},c).done(function(b){var e=a(b.getBody()).find("#add_section_numsections"),f=function(){if(""+parseInt(e.val())===e.val()&&1<=parseInt(e.val())){document.location=c.attr("href")+"&numsections="+parseInt(e.val())}};b.setSaveButtonText(d);b.getRoot().on(i.shown,function(){e.focus().select().on("keydown",function(a){if(a.keyCode===j.enter){f()}})});b.getRoot().on(i.save,function(a){a.preventDefault();f()})})})},replaceSectionActionItem:function replaceSectionActionItem(a,b,c,d,e,f){k.debug("replaceSectionActionItem() is deprecated and will be removed.");var g=a.find(s.SECTIONACTIONMENU+" "+b);I(g,c,d,e,f)},refreshModule:F,refreshSection:function refreshSection(c,e,f){if(f===void 0){f=p.sectionReturn}var g=a(c),h="refresh",i=b.call([{methodname:"core_course_edit_section",args:{id:e,action:h,sectionreturn:f}}],!0),j=x(g);return new Promise(function(b,c){a.when.apply(a,i).done(function(c){z(g,j);var d=a.parseJSON(c),f=a(d.content);g.replaceWith(f);a("".concat(s.SECTIONLI,"#").concat(e," ").concat(s.ACTIVITYLI)).each(function(a,b){B(b.data("id"))});var i=t(n.sectionRefreshed,{ajaxreturn:d,action:h,newSectionElement:f.get(0)},f);if(!i.defaultPrevented){J(f,a(s.SECTIONLI+"#"+e),d,q,e)}b(d)}).fail(function(a){var b=t("coursesectionrefreshfailed",{exception:a,action:h},g);if(!b.defaultPrevented){d.exception(a)}c()})})}}}); +define ("core_course/actions",["jquery","core/ajax","core/templates","core/notification","core/str","core/url","core/yui","core/modal_factory","core/modal_events","core/key_codes","core/log","core_courseformat/courseeditor","core/event_dispatcher","core_course/events"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){var o=["moveSection","moveCm","addSection","deleteSection"],p=l.getCurrentCourseEditor(),q,r={EDITINPROGRESS:"editinprogress",SECTIONDRAGGABLE:"sectiondraggable",EDITINGMOVE:"editing_move"},s={ACTIVITYLI:"li.activity",ACTIONAREA:".actions",ACTIVITYACTION:"a.cm-edit-action",MENU:".moodle-actionmenu[data-enhance=moodle-core-actionmenu]",TOGGLE:".toggle-display,.dropdown-toggle",SECTIONLI:"li.section",SECTIONACTIONMENU:".section_action_menu",ADDSECTIONS:".changenumsections [data-add-sections]"};g.use("moodle-course-coursebase",function(){var a=M.course.format.get_section_selector();if(a){s.SECTIONLI=a}});var t=function(a,b,c,d){if(!(c instanceof Element)&&c.get!==void 0){c=c.get(0)}return m.dispatchEvent(a,b,c,d)},u=function(a){var b=a.get(0);if(b.dataset.id){return b.dataset.id}var c;g.use("moodle-course-util",function(a){c=a.Moodle.core_course.util.cm.getId(a.Node(b))});return c},v=function(a){var b;g.use("moodle-course-util",function(c){b=c.Moodle.core_course.util.cm.getName(c.Node(a.get(0)))});var c=p.state,d=u(a);if(!b&&c&&d){var e;b=null===(e=c.cm.get(d))||void 0===e?void 0:e.name}return b},w=function(a){a.addClass(r.EDITINPROGRESS);var b=a.find(s.ACTIONAREA).get(0);if(b){var c=M.util.add_spinner(g,g.Node(b));c.show();if(a.data("id")!==void 0){p.dispatch("cmLock",[a.data("id")],!0)}return c}return null},x=function(a){a.addClass(r.EDITINPROGRESS);var b=a.find(s.SECTIONACTIONMENU).get(0);if(b){var c=M.util.add_spinner(g,g.Node(b));c.show();if(a.data("id")!==void 0){p.dispatch("sectionLock",[a.data("id")],!0)}return c}return null},y=function(a){var b=M.util.add_lightbox(g,g.Node(a.get(0)));b.show();return b},z=function(a,b,c){window.setTimeout(function(){a.removeClass(r.EDITINPROGRESS);if(b){b.hide()}if(a.data("id")!==void 0){var c="section"===a.data("for")?"sectionLock":"cmLock";p.dispatch(c,[a.data("id")],!1)}},c)},A=function(a,b){if(a){window.setTimeout(function(){a.hide()},b)}},B=function(a){g.use("moodle-course-coursebase",function(){M.course.coursebase.invoke_function("setup_for_resource","#"+a)});if(M.core.actionmenu&&M.core.actionmenu.newDOMNode){M.core.actionmenu.newDOMNode(g.one("#"+a))}},C=function(b,c){var d=a("#"+b),e="[data-action="+c+"]";if("groupsseparate"===c||"groupsvisible"===c||"groupsnone"===c){e="[data-action=groupsseparate],[data-action=groupsvisible],[data-action=groupsnone]"}if(d.find(e).is(":visible")){d.find(e).focus()}else{d.find(s.MENU).find(s.TOGGLE).focus()}},D=function(b){var c=a("a:visible"),d=!1,e=null;c.each(function(){if(a.contains(b[0],this)){d=!0}else if(d){e=this;return!1}return!0});return e},E=function(c,e,f){var g=f.attr("data-action"),h=w(c),i=b.call([{methodname:"core_course_edit_module",args:{id:e,action:g,sectionreturn:f.attr("data-sectionreturn")?f.attr("data-sectionreturn"):0}}],!0),j;if("duplicate"===g){j=y(f.closest(s.SECTIONLI))}a.when.apply(a,i).done(function(b){var d=D(c);c.replaceWith(b);var f=[];a("
"+b+"
").find(s.ACTIVITYLI).each(function(b){B(a(this).attr("id"));if(0===b){C(a(this).attr("id"),g);d=null}f.push(u(a(this)))});if(d){d.focus()}z(c,h,400);A(j,400);c.trigger(a.Event("coursemoduleedited",{ajaxreturn:b,action:g}));p.dispatch("legacyActivityAction",g,e,f)}).fail(function(b){z(c,h);A(j);var f=a.Event("coursemoduleeditfailed",{exception:b,action:g});c.trigger(f);if(!f.isDefaultPrevented()){d.exception(b)}})},F=function(c,d,e){if(e===void 0){e=p.sectionReturn}var f=a(c),g=w(f),h=b.call([{methodname:"core_course_get_module",args:{id:d,sectionreturn:e}}],!0);return new Promise(function(b,c){a.when.apply(a,h).done(function(a){z(f,g,400);L(a);b(a)}).fail(function(){z(f,g);c()})})},G=function(a,b){var c=a.attr("class").match(/modtype_([^\s]*)/)[1],f=v(a);e.get_string("pluginname",c).done(function(a){e.get_strings([{key:"confirm",component:"core"},{key:null===f?"deletechecktype":"deletechecktypename",param:{type:a,name:f}},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],b)})})},H=function(a,b){e.get_strings([{key:"confirm"},{key:"yes"},{key:"no"}]).done(function(c){d.confirm(c[0],a,c[1],c[2],b)})},I=function(a,b,f,g,h){return e.get_strings([{key:f,component:g}]).then(function(d){a.find("span.menu-action-text").html(d[0]);return c.renderPix(b,"core")}).then(function(b){a.find(".icon").replaceWith(b);a.attr("data-action",h)}).catch(d.exception)},J=function(b,c,d,e,f){var g=c.attr("data-action");if("hide"===g||"show"===g){if("hide"===g){b.addClass("hidden");I(c,"i/show","showfromothers","format_"+e,"show")}else{b.removeClass("hidden");I(c,"i/hide","hidefromothers","format_"+e,"hide")}if(d.modules!==void 0){for(var h in d.modules){L(d.modules[h])}}if(d.section_availability!==void 0){b.find(".section_availability").first().replaceWith(d.section_availability)}var k=p.state.section.get(f);if(k!==void 0){p.dispatch("sectionState",[f])}}else if("setmarker"===g){var i=a(s.SECTIONLI+".current"),j=i.find(s.SECTIONACTIONMENU+" a[data-action=removemarker]");i.removeClass("current");I(j,"i/marker","highlight","core","setmarker");b.addClass("current");I(c,"i/marked","highlightoff","core","removemarker");p.dispatch("legacySectionAction",g,f)}else if("removemarker"===g){b.removeClass("current");I(c,"i/marker","highlight","core","setmarker");p.dispatch("legacySectionAction",g,f)}},K=function(a){var b=document.getElementById(a);if(!b||!b.contains(document.activeElement)){return}if(b.querySelector(s.ACTIONAREA).contains(document.activeElement)){return"".concat(s.ACTIONAREA," [tabindex=\"0\"]")}if(document.activeElement.id){return"#".concat(document.activeElement.id)}},L=function(b){a("
"+b+"
").find(s.ACTIVITYLI).each(function(){var c=a(this).attr("id"),d=K(c);a(s.ACTIVITYLI+"#"+c).replaceWith(b);B(c);if(d){var e,f=document.getElementById(c);null===(e=f.querySelector(d))||void 0===e?void 0:e.focus()}})},N=function(c,e,f,g){var h=f.attr("data-action"),i=f.attr("data-sectionreturn")?f.attr("data-sectionreturn"):0;if(p.supportComponents&&o.includes(h)){return!1}var j=x(c),k=b.call([{methodname:"core_course_edit_section",args:{id:e,action:h,sectionreturn:i}}],!0),l=y(c);a.when.apply(a,k).done(function(b){var d=a.parseJSON(b);z(c,j);A(l);c.find(s.SECTIONACTIONMENU).find(s.TOGGLE).focus();var i=a.Event("coursesectionedited",{ajaxreturn:d,action:h});c.trigger(i);if(!i.isDefaultPrevented()){J(c,f,d,g,e)}}).fail(function(b){z(c,j);A(l);var f=a.Event("coursesectioneditfailed",{exception:b,action:h});c.trigger(f);if(!f.isDefaultPrevented()){d.exception(b)}});return!0};g.use("moodle-course-coursebase",function(){M.course.coursebase.register_module({set_visibility_resource_ui:function set_visibility_resource_ui(b){var c=a(b.element.getDOMNode()),d=u(c);if(d){var e=c.find("."+r.EDITINGMOVE).attr("data-sectionreturn");F(c,d,e)}},updateMovedCmState:function updateMovedCmState(a){var b=p.state,c=b.cm.get(a.cmid);if(c!==void 0){p.dispatch("sectionState",[c.sectionid])}p.dispatch("cmState",[a.cmid])},updateMovedSectionState:function updateMovedSectionState(){p.dispatch("courseState")}})});p.addMutations({legacyActivityAction:function legacyActivityAction(a,b,c,d){var e=a.state,f=e.cm.get(c);if(f===void 0){return}var g=e.section.get(f.sectionid);if(g===void 0){return}a.setReadOnly(!1);f.locked=!0;a.setReadOnly(!0);a.setReadOnly(!1);f.locked=!1;switch(b){case"delete":g.cmlist=g.cmlist.reduce(function(a,b){if(b!=c){a.push(b)}return a},[]);e.cm.delete(c);break;case"hide":case"show":f.visible="show"===b?!0:!1;break;case"duplicate":p.dispatch("cmState",d);break;}a.setReadOnly(!0)},legacySectionAction:function legacySectionAction(a,b,c){var d=a.state,e=d.section.get(c);if(e===void 0){return}a.setReadOnly(!1);e.locked=!0;a.setReadOnly(!0);a.setReadOnly(!1);e.locked=!1;switch(b){case"setmarker":d.section.forEach(function(a){if(a.id!=c){a.current=!1}});e.current=!0;break;case"removemarker":e.current=!1;break;}a.setReadOnly(!0)}});return{initCoursePage:function initCoursePage(b){q=b;a("body").on("click keypress",s.ACTIVITYLI+" "+s.ACTIVITYACTION+"[data-action]",function(b){if("keypress"===b.type&&13!==b.keyCode){return}var c=a(this),d=c.closest(s.ACTIVITYLI),e=c.attr("data-action"),f=u(d);switch(e){case"moveleft":case"moveright":case"delete":case"duplicate":case"hide":case"stealth":case"show":case"groupsseparate":case"groupsvisible":case"groupsnone":break;default:return;}if(!f){return}b.preventDefault();if("delete"===e){G(d,function(){E(d,f,c)})}else{E(d,f,c)}});a("body").on("click keypress",s.SECTIONLI+" "+s.SECTIONACTIONMENU+"[data-sectionid] a[data-action]",function(c){if("keypress"===c.type&&13!==c.keyCode){return}var d=a(this),e=d.closest(s.SECTIONLI),f=d.closest(s.SECTIONACTIONMENU).attr("data-sectionid"),g=!0;if(d.attr("data-confirm")){H(d.attr("data-confirm"),function(){g=N(e,f,d,b)})}else{g=N(e,f,d,b)}if(g){c.preventDefault()}});a("body").on("updated","".concat(s.SECTIONLI," [data-inplaceeditable]"),function(a){if(a.ajaxreturn&&a.ajaxreturn.itemid){var b=p.state,c=b.section.get(a.ajaxreturn.itemid);if(c!==void 0){p.dispatch("sectionState",[a.ajaxreturn.itemid])}}});a("body").on("updated","".concat(s.ACTIVITYLI," [data-inplaceeditable]"),function(a){if(a.ajaxreturn&&a.ajaxreturn.itemid){p.dispatch("cmState",[a.ajaxreturn.itemid])}});if(p.supportComponents&&o.includes("addSection")){return}e.get_string("numberweeks").done(function(b){var c=a(s.ADDSECTIONS),d=c.attr("data-add-sections"),e=c.attr("data-new-sections"),f=a("
");f.find("label").html(b);h.create({title:d,type:h.types.SAVE_CANCEL,body:f.html()},c).done(function(b){var e=a(b.getBody()).find("#add_section_numsections"),f=function(){if(""+parseInt(e.val())===e.val()&&1<=parseInt(e.val())){document.location=c.attr("href")+"&numsections="+parseInt(e.val())}};b.setSaveButtonText(d);b.getRoot().on(i.shown,function(){e.focus().select().on("keydown",function(a){if(a.keyCode===j.enter){f()}})});b.getRoot().on(i.save,function(a){a.preventDefault();f()})})})},replaceSectionActionItem:function replaceSectionActionItem(a,b,c,d,e,f){k.debug("replaceSectionActionItem() is deprecated and will be removed.");var g=a.find(s.SECTIONACTIONMENU+" "+b);I(g,c,d,e,f)},refreshModule:F,refreshSection:function refreshSection(c,e,f){if(f===void 0){f=p.sectionReturn}var g=a(c),h="refresh",i=b.call([{methodname:"core_course_edit_section",args:{id:e,action:h,sectionreturn:f}}],!0),j=x(g);return new Promise(function(b,c){a.when.apply(a,i).done(function(c){z(g,j);var d=a.parseJSON(c),f=a(d.content);g.replaceWith(f);a("".concat(s.SECTIONLI,"#").concat(e," ").concat(s.ACTIVITYLI)).each(function(a,b){B(b.data("id"))});var i=t(n.sectionRefreshed,{ajaxreturn:d,action:h,newSectionElement:f.get(0)},f);if(!i.defaultPrevented){J(f,a(s.SECTIONLI+"#"+e),d,q,e)}b(d)}).fail(function(a){var b=t("coursesectionrefreshfailed",{exception:a,action:h},g);if(!b.defaultPrevented){d.exception(a)}c()})})}}}); //# sourceMappingURL=actions.min.js.map diff --git a/course/amd/build/actions.min.js.map b/course/amd/build/actions.min.js.map index 3d4218153e8..681509f9cb2 100644 --- a/course/amd/build/actions.min.js.map +++ b/course/amd/build/actions.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/actions.js"],"names":["define","$","ajax","templates","notification","str","url","Y","ModalFactory","ModalEvents","KeyCodes","log","editor","EventDispatcher","CourseEvents","componentActions","courseeditor","getCurrentCourseEditor","formatname","CSS","EDITINPROGRESS","SECTIONDRAGGABLE","EDITINGMOVE","SELECTOR","ACTIVITYLI","ACTIONAREA","ACTIVITYACTION","MENU","TOGGLE","SECTIONLI","SECTIONACTIONMENU","ADDSECTIONS","use","courseformatselector","M","course","format","get_section_selector","dispatchEvent","eventName","detail","container","options","Element","get","getModuleId","element","item","dataset","id","Moodle","core_course","util","cm","getId","Node","getModuleName","name","getName","state","cmid","addActivitySpinner","activity","addClass","actionarea","find","spinner","add_spinner","show","data","dispatch","addSectionSpinner","sectionelement","addSectionLightbox","lightbox","add_lightbox","removeSpinner","delay","window","setTimeout","removeClass","hide","mutation","removeLightbox","initActionMenu","elementid","coursebase","invoke_function","core","actionmenu","newDOMNode","one","focusActionItem","elementId","action","mainelement","selector","is","focus","findNextFocusable","mainElement","tabables","isInside","foundElement","each","contains","editModule","moduleElement","target","attr","promises","call","methodname","args","sectionreturn","closest","when","apply","done","elementToFocus","replaceWith","affectedids","index","push","trigger","Event","ajaxreturn","fail","ex","e","exception","isDefaultPrevented","refreshModule","sectionReturn","activityElement","Promise","resolve","reject","replaceActivityHtmlWith","confirmDeleteModule","onconfirm","modtypename","match","modulename","get_string","pluginname","get_strings","key","component","param","type","s","confirm","confirmEditSection","message","replaceActionItem","actionitem","image","stringname","stringcomponent","newaction","then","strings","html","renderPix","pixhtml","catch","defaultEditSectionHandler","sectionElement","actionItem","courseformat","sectionid","modules","i","section_availability","first","section","oldmarker","oldActionItem","activityHTML","editSection","supportComponents","includes","dataencoded","parseJSON","register_module","set_visibility_resource_ui","getDOMNode","updateMovedCmState","params","updateMovedSectionState","addMutations","legacyActivityAction","statemanager","setReadOnly","locked","cmlist","reduce","current","delete","visible","legacySectionAction","forEach","initCoursePage","on","keyCode","moduleId","preventDefault","sectionId","isExecuted","itemid","strNumberSections","modalTitle","newSections","modalBody","create","title","types","SAVE_CANCEL","body","modal","numSections","getBody","addSections","parseInt","val","document","location","setSaveButtonText","getRoot","shown","select","enter","save","replaceSectionActionItem","debug","refreshSection","newSectionElement","content","event","sectionRefreshed","defaultPrevented"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Various actions on modules and sections in the editing mode - hiding, duplicating, deleting, etc.\n *\n * @module core_course/actions\n * @copyright 2016 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.3\n */\ndefine(\n [\n 'jquery',\n 'core/ajax',\n 'core/templates',\n 'core/notification',\n 'core/str',\n 'core/url',\n 'core/yui',\n 'core/modal_factory',\n 'core/modal_events',\n 'core/key_codes',\n 'core/log',\n 'core_courseformat/courseeditor',\n 'core/event_dispatcher',\n 'core_course/events'\n ],\n function(\n $,\n ajax,\n templates,\n notification,\n str,\n url,\n Y,\n ModalFactory,\n ModalEvents,\n KeyCodes,\n log,\n editor,\n EventDispatcher,\n CourseEvents\n ) {\n\n // Eventually, core_courseformat/local/content/actions will handle all actions for\n // component compatible formats and the default actions.js won't be necessary anymore.\n // Meanwhile, we filter the migrated actions.\n const componentActions = ['moveSection', 'moveCm', 'addSection', 'deleteSection'];\n\n // The course reactive instance.\n const courseeditor = editor.getCurrentCourseEditor();\n\n // The current course format name (loaded on init).\n let formatname;\n\n var CSS = {\n EDITINPROGRESS: 'editinprogress',\n SECTIONDRAGGABLE: 'sectiondraggable',\n EDITINGMOVE: 'editing_move'\n };\n var SELECTOR = {\n ACTIVITYLI: 'li.activity',\n ACTIONAREA: '.actions',\n ACTIVITYACTION: 'a.cm-edit-action',\n MENU: '.moodle-actionmenu[data-enhance=moodle-core-actionmenu]',\n TOGGLE: '.toggle-display,.dropdown-toggle',\n SECTIONLI: 'li.section',\n SECTIONACTIONMENU: '.section_action_menu',\n ADDSECTIONS: '.changenumsections [data-add-sections]'\n };\n\n Y.use('moodle-course-coursebase', function() {\n var courseformatselector = M.course.format.get_section_selector();\n if (courseformatselector) {\n SELECTOR.SECTIONLI = courseformatselector;\n }\n });\n\n /**\n * Dispatch event wrapper.\n *\n * Old jQuery events will be replaced by native events gradually.\n *\n * @method dispatchEvent\n * @param {String} eventName The name of the event\n * @param {Object} detail Any additional details to pass into the eveent\n * @param {Node|HTMLElement} container The point at which to dispatch the event\n * @param {Object} options\n * @param {Boolean} options.bubbles Whether to bubble up the DOM\n * @param {Boolean} options.cancelable Whether preventDefault() can be called\n * @param {Boolean} options.composed Whether the event can bubble across the ShadowDOM boundary\n * @returns {CustomEvent}\n */\n const dispatchEvent = function(eventName, detail, container, options) {\n // Most actions still uses jQuery node instead of regular HTMLElement.\n if (!(container instanceof Element) && container.get !== undefined) {\n container = container.get(0);\n }\n return EventDispatcher.dispatchEvent(eventName, detail, container, options);\n };\n\n /**\n * Wrapper for Y.Moodle.core_course.util.cm.getId\n *\n * @param {JQuery} element\n * @returns {Integer}\n */\n var getModuleId = function(element) {\n // Check if we have a data-id first.\n const item = element.get(0);\n if (item.dataset.id) {\n return item.dataset.id;\n }\n // Use YUI way if data-id is not present.\n let id;\n Y.use('moodle-course-util', function(Y) {\n id = Y.Moodle.core_course.util.cm.getId(Y.Node(item));\n });\n return id;\n };\n\n /**\n * Wrapper for Y.Moodle.core_course.util.cm.getName\n *\n * @param {JQuery} element\n * @returns {String}\n */\n var getModuleName = function(element) {\n var name;\n Y.use('moodle-course-util', function(Y) {\n name = Y.Moodle.core_course.util.cm.getName(Y.Node(element.get(0)));\n });\n // Check if we have the name in the course state.\n const state = courseeditor.state;\n const cmid = getModuleId(element);\n if (!name && state && cmid) {\n name = state.cm.get(cmid)?.name;\n }\n return name;\n };\n\n /**\n * Wrapper for M.util.add_spinner for an activity\n *\n * @param {JQuery} activity\n * @returns {Node}\n */\n var addActivitySpinner = function(activity) {\n activity.addClass(CSS.EDITINPROGRESS);\n var actionarea = activity.find(SELECTOR.ACTIONAREA).get(0);\n if (actionarea) {\n var spinner = M.util.add_spinner(Y, Y.Node(actionarea));\n spinner.show();\n // Lock the activity state element.\n if (activity.data('id') !== undefined) {\n courseeditor.dispatch('cmLock', [activity.data('id')], true);\n }\n return spinner;\n }\n return null;\n };\n\n /**\n * Wrapper for M.util.add_spinner for a section\n *\n * @param {JQuery} sectionelement\n * @returns {Node}\n */\n var addSectionSpinner = function(sectionelement) {\n sectionelement.addClass(CSS.EDITINPROGRESS);\n var actionarea = sectionelement.find(SELECTOR.SECTIONACTIONMENU).get(0);\n if (actionarea) {\n var spinner = M.util.add_spinner(Y, Y.Node(actionarea));\n spinner.show();\n // Lock the section state element.\n if (sectionelement.data('id') !== undefined) {\n courseeditor.dispatch('sectionLock', [sectionelement.data('id')], true);\n }\n return spinner;\n }\n return null;\n };\n\n /**\n * Wrapper for M.util.add_lightbox\n *\n * @param {JQuery} sectionelement\n * @returns {Node}\n */\n var addSectionLightbox = function(sectionelement) {\n var lightbox = M.util.add_lightbox(Y, Y.Node(sectionelement.get(0)));\n lightbox.show();\n return lightbox;\n };\n\n /**\n * Removes the spinner element\n *\n * @param {JQuery} element\n * @param {Node} spinner\n * @param {Number} delay\n */\n var removeSpinner = function(element, spinner, delay) {\n window.setTimeout(function() {\n element.removeClass(CSS.EDITINPROGRESS);\n if (spinner) {\n spinner.hide();\n }\n // Unlock the state element.\n if (element.data('id') !== undefined) {\n const mutation = (element.data('for') === 'section') ? 'sectionLock' : 'cmLock';\n courseeditor.dispatch(mutation, [element.data('id')], false);\n }\n }, delay);\n };\n\n /**\n * Removes the lightbox element\n *\n * @param {Node} lightbox lighbox YUI element returned by addSectionLightbox\n * @param {Number} delay\n */\n var removeLightbox = function(lightbox, delay) {\n if (lightbox) {\n window.setTimeout(function() {\n lightbox.hide();\n }, delay);\n }\n };\n\n /**\n * Initialise action menu for the element (section or module)\n *\n * @param {String} elementid CSS id attribute of the element\n */\n var initActionMenu = function(elementid) {\n // Initialise action menu in the new activity.\n Y.use('moodle-course-coursebase', function() {\n M.course.coursebase.invoke_function('setup_for_resource', '#' + elementid);\n });\n if (M.core.actionmenu && M.core.actionmenu.newDOMNode) {\n M.core.actionmenu.newDOMNode(Y.one('#' + elementid));\n }\n };\n\n /**\n * Returns focus to the element that was clicked or \"Edit\" link if element is no longer visible.\n *\n * @param {String} elementId CSS id attribute of the element\n * @param {String} action data-action property of the element that was clicked\n */\n var focusActionItem = function(elementId, action) {\n var mainelement = $('#' + elementId);\n var selector = '[data-action=' + action + ']';\n if (action === 'groupsseparate' || action === 'groupsvisible' || action === 'groupsnone') {\n // New element will have different data-action.\n selector = '[data-action=groupsseparate],[data-action=groupsvisible],[data-action=groupsnone]';\n }\n if (mainelement.find(selector).is(':visible')) {\n mainelement.find(selector).focus();\n } else {\n // Element not visible, focus the \"Edit\" link.\n mainelement.find(SELECTOR.MENU).find(SELECTOR.TOGGLE).focus();\n }\n };\n\n /**\n * Find next after the element\n *\n * @param {JQuery} mainElement element that is about to be deleted\n * @returns {JQuery}\n */\n var findNextFocusable = function(mainElement) {\n var tabables = $(\"a:visible\");\n var isInside = false;\n var foundElement = null;\n tabables.each(function() {\n if ($.contains(mainElement[0], this)) {\n isInside = true;\n } else if (isInside) {\n foundElement = this;\n return false; // Returning false in .each() is equivalent to \"break;\" inside the loop in php.\n }\n return true;\n });\n return foundElement;\n };\n\n /**\n * Performs an action on a module (moving, deleting, duplicating, hiding, etc.)\n *\n * @param {JQuery} moduleElement activity element we perform action on\n * @param {Number} cmid\n * @param {JQuery} target the element (menu item) that was clicked\n */\n var editModule = function(moduleElement, cmid, target) {\n var action = target.attr('data-action');\n var spinner = addActivitySpinner(moduleElement);\n var promises = ajax.call([{\n methodname: 'core_course_edit_module',\n args: {id: cmid,\n action: action,\n sectionreturn: target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : 0\n }\n }], true);\n\n var lightbox;\n if (action === 'duplicate') {\n lightbox = addSectionLightbox(target.closest(SELECTOR.SECTIONLI));\n }\n $.when.apply($, promises)\n .done(function(data) {\n var elementToFocus = findNextFocusable(moduleElement);\n moduleElement.replaceWith(data);\n let affectedids = [];\n // Initialise action menu for activity(ies) added as a result of this.\n $('
' + data + '
').find(SELECTOR.ACTIVITYLI).each(function(index) {\n initActionMenu($(this).attr('id'));\n if (index === 0) {\n focusActionItem($(this).attr('id'), action);\n elementToFocus = null;\n }\n // Save any activity id in cmids.\n affectedids.push(getModuleId($(this)));\n });\n // In case of activity deletion focus the next focusable element.\n if (elementToFocus) {\n elementToFocus.focus();\n }\n // Remove spinner and lightbox with a delay.\n removeSpinner(moduleElement, spinner, 400);\n removeLightbox(lightbox, 400);\n // Trigger event that can be observed by course formats.\n moduleElement.trigger($.Event('coursemoduleedited', {ajaxreturn: data, action: action}));\n\n // Modify cm state.\n courseeditor.dispatch('legacyActivityAction', action, cmid, affectedids);\n\n }).fail(function(ex) {\n // Remove spinner and lightbox.\n removeSpinner(moduleElement, spinner);\n removeLightbox(lightbox);\n // Trigger event that can be observed by course formats.\n var e = $.Event('coursemoduleeditfailed', {exception: ex, action: action});\n moduleElement.trigger(e);\n if (!e.isDefaultPrevented()) {\n notification.exception(ex);\n }\n });\n };\n\n /**\n * Requests html for the module via WS core_course_get_module and updates the module on the course page\n *\n * Used after d&d of the module to another section\n *\n * @param {JQuery|Element} element\n * @param {Number} cmid\n * @param {Number} sectionreturn\n * @return {Promise} the refresh promise\n */\n var refreshModule = function(element, cmid, sectionreturn) {\n\n if (sectionreturn === undefined) {\n sectionreturn = courseeditor.sectionReturn;\n }\n\n const activityElement = $(element);\n var spinner = addActivitySpinner(activityElement);\n var promises = ajax.call([{\n methodname: 'core_course_get_module',\n args: {id: cmid, sectionreturn: sectionreturn}\n }], true);\n\n return new Promise((resolve, reject) => {\n $.when.apply($, promises)\n .done(function(data) {\n removeSpinner(activityElement, spinner, 400);\n replaceActivityHtmlWith(data);\n resolve(data);\n }).fail(function() {\n removeSpinner(activityElement, spinner);\n reject();\n });\n });\n };\n\n /**\n * Requests html for the section via WS core_course_edit_section and updates the section on the course page\n *\n * @param {JQuery|Element} element\n * @param {Number} sectionid\n * @param {Number} sectionreturn\n * @return {Promise} the refresh promise\n */\n var refreshSection = function(element, sectionid, sectionreturn) {\n\n if (sectionreturn === undefined) {\n sectionreturn = courseeditor.sectionReturn;\n }\n\n const sectionElement = $(element);\n const action = 'refresh';\n const promises = ajax.call([{\n methodname: 'core_course_edit_section',\n args: {id: sectionid, action, sectionreturn},\n }], true);\n\n var spinner = addSectionSpinner(sectionElement);\n return new Promise((resolve, reject) => {\n $.when.apply($, promises)\n .done(dataencoded => {\n\n removeSpinner(sectionElement, spinner);\n const data = $.parseJSON(dataencoded);\n\n const newSectionElement = $(data.content);\n sectionElement.replaceWith(newSectionElement);\n\n // Init modules menus.\n $(`${SELECTOR.SECTIONLI}#${sectionid} ${SELECTOR.ACTIVITYLI}`).each(\n (index, activity) => {\n initActionMenu(activity.data('id'));\n }\n );\n\n // Trigger event that can be observed by course formats.\n const event = dispatchEvent(\n CourseEvents.sectionRefreshed,\n {\n ajaxreturn: data,\n action: action,\n newSectionElement: newSectionElement.get(0),\n },\n newSectionElement\n );\n\n if (!event.defaultPrevented) {\n defaultEditSectionHandler(\n newSectionElement, $(SELECTOR.SECTIONLI + '#' + sectionid),\n data,\n formatname,\n sectionid\n );\n }\n resolve(data);\n }).fail(ex => {\n // Trigger event that can be observed by course formats.\n const event = dispatchEvent(\n 'coursesectionrefreshfailed',\n {exception: ex, action: action},\n sectionElement\n );\n if (!event.defaultPrevented) {\n notification.exception(ex);\n }\n reject();\n });\n });\n };\n\n /**\n * Displays the delete confirmation to delete a module\n *\n * @param {JQuery} mainelement activity element we perform action on\n * @param {function} onconfirm function to execute on confirm\n */\n var confirmDeleteModule = function(mainelement, onconfirm) {\n var modtypename = mainelement.attr('class').match(/modtype_([^\\s]*)/)[1];\n var modulename = getModuleName(mainelement);\n\n str.get_string('pluginname', modtypename).done(function(pluginname) {\n var plugindata = {\n type: pluginname,\n name: modulename\n };\n str.get_strings([\n {key: 'confirm', component: 'core'},\n {key: modulename === null ? 'deletechecktype' : 'deletechecktypename', param: plugindata},\n {key: 'yes'},\n {key: 'no'}\n ]).done(function(s) {\n notification.confirm(s[0], s[1], s[2], s[3], onconfirm);\n }\n );\n });\n };\n\n /**\n * Displays the delete confirmation to delete a section\n *\n * @param {String} message confirmation message\n * @param {function} onconfirm function to execute on confirm\n */\n var confirmEditSection = function(message, onconfirm) {\n str.get_strings([\n {key: 'confirm'}, // TODO link text\n {key: 'yes'},\n {key: 'no'}\n ]).done(function(s) {\n notification.confirm(s[0], message, s[1], s[2], onconfirm);\n }\n );\n };\n\n /**\n * Replaces an action menu item with another one (for example Show->Hide, Set marker->Remove marker)\n *\n * @param {JQuery} actionitem\n * @param {String} image new image name (\"i/show\", \"i/hide\", etc.)\n * @param {String} stringname new string for the action menu item\n * @param {String} stringcomponent\n * @param {String} newaction new value for data-action attribute of the link\n * @return {Promise} promise which is resolved when the replacement has completed\n */\n var replaceActionItem = function(actionitem, image, stringname,\n stringcomponent, newaction) {\n\n var stringRequests = [{key: stringname, component: stringcomponent}];\n // Do not provide an icon with duplicate, different text to the menu item.\n\n return str.get_strings(stringRequests).then(function(strings) {\n actionitem.find('span.menu-action-text').html(strings[0]);\n\n return templates.renderPix(image, 'core');\n }).then(function(pixhtml) {\n actionitem.find('.icon').replaceWith(pixhtml);\n actionitem.attr('data-action', newaction);\n return;\n }).catch(notification.exception);\n };\n\n /**\n * Default post-processing for section AJAX edit actions.\n *\n * This can be overridden in course formats by listening to event coursesectionedited:\n *\n * $('body').on('coursesectionedited', 'li.section', function(e) {\n * var action = e.action,\n * sectionElement = $(e.target),\n * data = e.ajaxreturn;\n * // ... Do some processing here.\n * e.preventDefault(); // Prevent default handler.\n * });\n *\n * @param {JQuery} sectionElement\n * @param {JQuery} actionItem\n * @param {Object} data\n * @param {String} courseformat\n * @param {Number} sectionid\n */\n var defaultEditSectionHandler = function(sectionElement, actionItem, data, courseformat, sectionid) {\n var action = actionItem.attr('data-action');\n if (action === 'hide' || action === 'show') {\n if (action === 'hide') {\n sectionElement.addClass('hidden');\n replaceActionItem(actionItem, 'i/show',\n 'showfromothers', 'format_' + courseformat, 'show');\n } else {\n sectionElement.removeClass('hidden');\n replaceActionItem(actionItem, 'i/hide',\n 'hidefromothers', 'format_' + courseformat, 'hide');\n }\n // Replace the modules with new html (that indicates that they are now hidden or not hidden).\n if (data.modules !== undefined) {\n for (var i in data.modules) {\n replaceActivityHtmlWith(data.modules[i]);\n }\n }\n // Replace the section availability information.\n if (data.section_availability !== undefined) {\n sectionElement.find('.section_availability').first().replaceWith(data.section_availability);\n }\n // Modify course state.\n const section = courseeditor.state.section.get(sectionid);\n if (section !== undefined) {\n courseeditor.dispatch('sectionState', [sectionid]);\n }\n } else if (action === 'setmarker') {\n var oldmarker = $(SELECTOR.SECTIONLI + '.current'),\n oldActionItem = oldmarker.find(SELECTOR.SECTIONACTIONMENU + ' ' + 'a[data-action=removemarker]');\n oldmarker.removeClass('current');\n replaceActionItem(oldActionItem, 'i/marker',\n 'highlight', 'core', 'setmarker');\n sectionElement.addClass('current');\n replaceActionItem(actionItem, 'i/marked',\n 'highlightoff', 'core', 'removemarker');\n courseeditor.dispatch('legacySectionAction', action, sectionid);\n } else if (action === 'removemarker') {\n sectionElement.removeClass('current');\n replaceActionItem(actionItem, 'i/marker',\n 'highlight', 'core', 'setmarker');\n courseeditor.dispatch('legacySectionAction', action, sectionid);\n }\n };\n\n /**\n * Replaces the course module with the new html (used to update module after it was edited or its visibility was changed).\n *\n * @param {String} activityHTML\n */\n var replaceActivityHtmlWith = function(activityHTML) {\n $('
' + activityHTML + '
').find(SELECTOR.ACTIVITYLI).each(function() {\n // Extract id from the new activity html.\n var id = $(this).attr('id');\n // Find the existing element with the same id and replace its contents with new html.\n $(SELECTOR.ACTIVITYLI + '#' + id).replaceWith(activityHTML);\n // Initialise action menu.\n initActionMenu(id);\n });\n };\n\n /**\n * Performs an action on a module (moving, deleting, duplicating, hiding, etc.)\n *\n * @param {JQuery} sectionElement section element we perform action on\n * @param {Nunmber} sectionid\n * @param {JQuery} target the element (menu item) that was clicked\n * @param {String} courseformat\n * @return {boolean} true the action call is sent to the server or false if it is ignored.\n */\n var editSection = function(sectionElement, sectionid, target, courseformat) {\n var action = target.attr('data-action'),\n sectionreturn = target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : 0;\n\n // Filter direct component handled actions.\n if (courseeditor.supportComponents && componentActions.includes(action)) {\n return false;\n }\n\n var spinner = addSectionSpinner(sectionElement);\n var promises = ajax.call([{\n methodname: 'core_course_edit_section',\n args: {id: sectionid, action: action, sectionreturn: sectionreturn}\n }], true);\n\n var lightbox = addSectionLightbox(sectionElement);\n $.when.apply($, promises)\n .done(function(dataencoded) {\n var data = $.parseJSON(dataencoded);\n removeSpinner(sectionElement, spinner);\n removeLightbox(lightbox);\n sectionElement.find(SELECTOR.SECTIONACTIONMENU).find(SELECTOR.TOGGLE).focus();\n // Trigger event that can be observed by course formats.\n var e = $.Event('coursesectionedited', {ajaxreturn: data, action: action});\n sectionElement.trigger(e);\n if (!e.isDefaultPrevented()) {\n defaultEditSectionHandler(sectionElement, target, data, courseformat, sectionid);\n }\n }).fail(function(ex) {\n // Remove spinner and lightbox.\n removeSpinner(sectionElement, spinner);\n removeLightbox(lightbox);\n // Trigger event that can be observed by course formats.\n var e = $.Event('coursesectioneditfailed', {exception: ex, action: action});\n sectionElement.trigger(e);\n if (!e.isDefaultPrevented()) {\n notification.exception(ex);\n }\n });\n return true;\n };\n\n // Register a function to be executed after D&D of an activity.\n Y.use('moodle-course-coursebase', function() {\n M.course.coursebase.register_module({\n // Ignore camelcase eslint rule for the next line because it is an expected name of the callback.\n // eslint-disable-next-line camelcase\n set_visibility_resource_ui: function(args) {\n var mainelement = $(args.element.getDOMNode());\n var cmid = getModuleId(mainelement);\n if (cmid) {\n var sectionreturn = mainelement.find('.' + CSS.EDITINGMOVE).attr('data-sectionreturn');\n refreshModule(mainelement, cmid, sectionreturn);\n }\n },\n /**\n * Update the course state when some cm is moved via YUI.\n * @param {*} params\n */\n updateMovedCmState: (params) => {\n const state = courseeditor.state;\n\n // Update old section.\n const cm = state.cm.get(params.cmid);\n if (cm !== undefined) {\n courseeditor.dispatch('sectionState', [cm.sectionid]);\n }\n // Update cm state.\n courseeditor.dispatch('cmState', [params.cmid]);\n },\n /**\n * Update the course state when some section is moved via YUI.\n */\n updateMovedSectionState: () => {\n courseeditor.dispatch('courseState');\n },\n });\n });\n\n // From Moodle 4.0 all edit actions are being re-implemented as state mutation.\n // This means all method from this \"actions\" module will be deprecated when all the course\n // interface is migrated to reactive components.\n // Most legacy actions did not provide enough information to regenarate the course so they\n // use the mutations courseState, sectionState and cmState to get the updated state from\n // the server. However, some activity actions where we can prevent an extra webservice\n // call by implementing an adhoc mutation.\n courseeditor.addMutations({\n /**\n * Compatibility function to update Moodle 4.0 course state using legacy actions.\n *\n * This method only updates some actions which does not require to use cmState mutation\n * to get updated data form the server.\n *\n * @param {Object} statemanager the current state in read write mode\n * @param {String} action the performed action\n * @param {Number} cmid the affected course module id\n * @param {Array} affectedids all affected cm ids (for duplicate action)\n */\n legacyActivityAction: function(statemanager, action, cmid, affectedids) {\n\n const state = statemanager.state;\n const cm = state.cm.get(cmid);\n if (cm === undefined) {\n return;\n }\n const section = state.section.get(cm.sectionid);\n if (section === undefined) {\n return;\n }\n\n // Send the element is locked. Reactive events are only triggered when the state\n // read only mode is restored. We want to notify the interface the element is\n // locked so we need to do a quick lock operation before performing the rest\n // of the mutation.\n statemanager.setReadOnly(false);\n cm.locked = true;\n statemanager.setReadOnly(true);\n\n // Now we do the real mutation.\n statemanager.setReadOnly(false);\n\n // This locked will take effect when the read only is restored.\n cm.locked = false;\n\n switch (action) {\n case 'delete':\n // Remove from section.\n section.cmlist = section.cmlist.reduce(\n (cmlist, current) => {\n if (current != cmid) {\n cmlist.push(current);\n }\n return cmlist;\n },\n []\n );\n // Delete form list.\n state.cm.delete(cmid);\n break;\n\n case 'hide':\n case 'show':\n cm.visible = (action === 'show') ? true : false;\n break;\n\n case 'duplicate':\n // Duplicate requires to get extra data from the server.\n courseeditor.dispatch('cmState', affectedids);\n break;\n }\n statemanager.setReadOnly(true);\n },\n legacySectionAction: function(statemanager, action, sectionid) {\n\n const state = statemanager.state;\n const section = state.section.get(sectionid);\n if (section === undefined) {\n return;\n }\n\n // Send the element is locked. Reactive events are only triggered when the state\n // read only mode is restored. We want to notify the interface the element is\n // locked so we need to do a quick lock operation before performing the rest\n // of the mutation.\n statemanager.setReadOnly(false);\n section.locked = true;\n statemanager.setReadOnly(true);\n\n // Now we do the real mutation.\n statemanager.setReadOnly(false);\n\n // This locked will take effect when the read only is restored.\n section.locked = false;\n\n switch (action) {\n case 'setmarker':\n // Remove previous marker.\n state.section.forEach((current) => {\n if (current.id != sectionid) {\n current.current = false;\n }\n });\n section.current = true;\n break;\n\n case 'removemarker':\n section.current = false;\n break;\n }\n statemanager.setReadOnly(true);\n },\n });\n\n return /** @alias module:core_course/actions */ {\n\n /**\n * Initialises course page\n *\n * @method init\n * @param {String} courseformat name of the current course format (for fetching strings)\n */\n initCoursePage: function(courseformat) {\n\n formatname = courseformat;\n\n // Add a handler for course module actions.\n $('body').on('click keypress', SELECTOR.ACTIVITYLI + ' ' +\n SELECTOR.ACTIVITYACTION + '[data-action]', function(e) {\n if (e.type === 'keypress' && e.keyCode !== 13) {\n return;\n }\n var actionItem = $(this),\n moduleElement = actionItem.closest(SELECTOR.ACTIVITYLI),\n action = actionItem.attr('data-action'),\n moduleId = getModuleId(moduleElement);\n switch (action) {\n case 'moveleft':\n case 'moveright':\n case 'delete':\n case 'duplicate':\n case 'hide':\n case 'stealth':\n case 'show':\n case 'groupsseparate':\n case 'groupsvisible':\n case 'groupsnone':\n break;\n default:\n // Nothing to do here!\n return;\n }\n if (!moduleId) {\n return;\n }\n e.preventDefault();\n if (action === 'delete') {\n // Deleting requires confirmation.\n confirmDeleteModule(moduleElement, function() {\n editModule(moduleElement, moduleId, actionItem);\n });\n } else {\n editModule(moduleElement, moduleId, actionItem);\n }\n });\n\n // Add a handler for section show/hide actions.\n $('body').on('click keypress', SELECTOR.SECTIONLI + ' ' +\n SELECTOR.SECTIONACTIONMENU + '[data-sectionid] ' +\n 'a[data-action]', function(e) {\n if (e.type === 'keypress' && e.keyCode !== 13) {\n return;\n }\n var actionItem = $(this),\n sectionElement = actionItem.closest(SELECTOR.SECTIONLI),\n sectionId = actionItem.closest(SELECTOR.SECTIONACTIONMENU).attr('data-sectionid');\n\n let isExecuted = true;\n if (actionItem.attr('data-confirm')) {\n // Action requires confirmation.\n confirmEditSection(actionItem.attr('data-confirm'), function() {\n isExecuted = editSection(sectionElement, sectionId, actionItem, courseformat);\n });\n } else {\n isExecuted = editSection(sectionElement, sectionId, actionItem, courseformat);\n }\n // Prevent any other module from capturing the action if it is already in execution.\n if (isExecuted) {\n e.preventDefault();\n }\n });\n\n // The section and activity names are edited using inplace editable.\n // The \"update\" jQuery event must be captured in order to update the course state.\n $('body').on('updated', `${SELECTOR.SECTIONLI} [data-inplaceeditable]`, function(e) {\n if (e.ajaxreturn && e.ajaxreturn.itemid) {\n const state = courseeditor.state;\n const section = state.section.get(e.ajaxreturn.itemid);\n if (section !== undefined) {\n courseeditor.dispatch('sectionState', [e.ajaxreturn.itemid]);\n }\n }\n });\n $('body').on('updated', `${SELECTOR.ACTIVITYLI} [data-inplaceeditable]`, function(e) {\n if (e.ajaxreturn && e.ajaxreturn.itemid) {\n courseeditor.dispatch('cmState', [e.ajaxreturn.itemid]);\n }\n });\n\n // Component-based formats don't use modals to create sections.\n if (courseeditor.supportComponents && componentActions.includes('addSection')) {\n return;\n }\n\n // Add a handler for \"Add sections\" link to ask for a number of sections to add.\n str.get_string('numberweeks').done(function(strNumberSections) {\n var trigger = $(SELECTOR.ADDSECTIONS),\n modalTitle = trigger.attr('data-add-sections'),\n newSections = trigger.attr('data-new-sections');\n var modalBody = $('
' +\n '
');\n modalBody.find('label').html(strNumberSections);\n ModalFactory.create({\n title: modalTitle,\n type: ModalFactory.types.SAVE_CANCEL,\n body: modalBody.html()\n }, trigger)\n .done(function(modal) {\n var numSections = $(modal.getBody()).find('#add_section_numsections'),\n addSections = function() {\n // Check if value of the \"Number of sections\" is a valid positive integer and redirect\n // to adding a section script.\n if ('' + parseInt(numSections.val()) === numSections.val() && parseInt(numSections.val()) >= 1) {\n document.location = trigger.attr('href') + '&numsections=' + parseInt(numSections.val());\n }\n };\n modal.setSaveButtonText(modalTitle);\n modal.getRoot().on(ModalEvents.shown, function() {\n // When modal is shown focus and select the input and add a listener to keypress of \"Enter\".\n numSections.focus().select().on('keydown', function(e) {\n if (e.keyCode === KeyCodes.enter) {\n addSections();\n }\n });\n });\n modal.getRoot().on(ModalEvents.save, function(e) {\n // When modal \"Add\" button is pressed.\n e.preventDefault();\n addSections();\n });\n });\n });\n },\n\n /**\n * Replaces a section action menu item with another one (for example Show->Hide, Set marker->Remove marker)\n *\n * This method can be used by course formats in their listener to the coursesectionedited event\n *\n * @deprecated since Moodle 3.9\n * @param {JQuery} sectionelement\n * @param {String} selector CSS selector inside the section element, for example \"a[data-action=show]\"\n * @param {String} image new image name (\"i/show\", \"i/hide\", etc.)\n * @param {String} stringname new string for the action menu item\n * @param {String} stringcomponent\n * @param {String} newaction new value for data-action attribute of the link\n */\n replaceSectionActionItem: function(sectionelement, selector, image, stringname,\n stringcomponent, newaction) {\n log.debug('replaceSectionActionItem() is deprecated and will be removed.');\n var actionitem = sectionelement.find(SELECTOR.SECTIONACTIONMENU + ' ' + selector);\n replaceActionItem(actionitem, image, stringname, stringcomponent, newaction);\n },\n // Method to refresh a module.\n refreshModule,\n refreshSection,\n };\n });\n"],"file":"actions.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/actions.js"],"names":["define","$","ajax","templates","notification","str","url","Y","ModalFactory","ModalEvents","KeyCodes","log","editor","EventDispatcher","CourseEvents","componentActions","courseeditor","getCurrentCourseEditor","formatname","CSS","EDITINPROGRESS","SECTIONDRAGGABLE","EDITINGMOVE","SELECTOR","ACTIVITYLI","ACTIONAREA","ACTIVITYACTION","MENU","TOGGLE","SECTIONLI","SECTIONACTIONMENU","ADDSECTIONS","use","courseformatselector","M","course","format","get_section_selector","dispatchEvent","eventName","detail","container","options","Element","get","getModuleId","element","item","dataset","id","Moodle","core_course","util","cm","getId","Node","getModuleName","name","getName","state","cmid","addActivitySpinner","activity","addClass","actionarea","find","spinner","add_spinner","show","data","dispatch","addSectionSpinner","sectionelement","addSectionLightbox","lightbox","add_lightbox","removeSpinner","delay","window","setTimeout","removeClass","hide","mutation","removeLightbox","initActionMenu","elementid","coursebase","invoke_function","core","actionmenu","newDOMNode","one","focusActionItem","elementId","action","mainelement","selector","is","focus","findNextFocusable","mainElement","tabables","isInside","foundElement","each","contains","editModule","moduleElement","target","attr","promises","call","methodname","args","sectionreturn","closest","when","apply","done","elementToFocus","replaceWith","affectedids","index","push","trigger","Event","ajaxreturn","fail","ex","e","exception","isDefaultPrevented","refreshModule","sectionReturn","activityElement","Promise","resolve","reject","replaceActivityHtmlWith","confirmDeleteModule","onconfirm","modtypename","match","modulename","get_string","pluginname","get_strings","key","component","param","type","s","confirm","confirmEditSection","message","replaceActionItem","actionitem","image","stringname","stringcomponent","newaction","then","strings","html","renderPix","pixhtml","catch","defaultEditSectionHandler","sectionElement","actionItem","courseformat","sectionid","modules","i","section_availability","first","section","oldmarker","oldActionItem","getActivityFocusedElement","document","getElementById","activeElement","querySelector","activityHTML","focusedPath","newItem","editSection","supportComponents","includes","dataencoded","parseJSON","register_module","set_visibility_resource_ui","getDOMNode","updateMovedCmState","params","updateMovedSectionState","addMutations","legacyActivityAction","statemanager","setReadOnly","locked","cmlist","reduce","current","delete","visible","legacySectionAction","forEach","initCoursePage","on","keyCode","moduleId","preventDefault","sectionId","isExecuted","itemid","strNumberSections","modalTitle","newSections","modalBody","create","title","types","SAVE_CANCEL","body","modal","numSections","getBody","addSections","parseInt","val","location","setSaveButtonText","getRoot","shown","select","enter","save","replaceSectionActionItem","debug","refreshSection","newSectionElement","content","event","sectionRefreshed","defaultPrevented"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Various actions on modules and sections in the editing mode - hiding, duplicating, deleting, etc.\n *\n * @module core_course/actions\n * @copyright 2016 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.3\n */\ndefine(\n [\n 'jquery',\n 'core/ajax',\n 'core/templates',\n 'core/notification',\n 'core/str',\n 'core/url',\n 'core/yui',\n 'core/modal_factory',\n 'core/modal_events',\n 'core/key_codes',\n 'core/log',\n 'core_courseformat/courseeditor',\n 'core/event_dispatcher',\n 'core_course/events'\n ],\n function(\n $,\n ajax,\n templates,\n notification,\n str,\n url,\n Y,\n ModalFactory,\n ModalEvents,\n KeyCodes,\n log,\n editor,\n EventDispatcher,\n CourseEvents\n ) {\n\n // Eventually, core_courseformat/local/content/actions will handle all actions for\n // component compatible formats and the default actions.js won't be necessary anymore.\n // Meanwhile, we filter the migrated actions.\n const componentActions = ['moveSection', 'moveCm', 'addSection', 'deleteSection'];\n\n // The course reactive instance.\n const courseeditor = editor.getCurrentCourseEditor();\n\n // The current course format name (loaded on init).\n let formatname;\n\n var CSS = {\n EDITINPROGRESS: 'editinprogress',\n SECTIONDRAGGABLE: 'sectiondraggable',\n EDITINGMOVE: 'editing_move'\n };\n var SELECTOR = {\n ACTIVITYLI: 'li.activity',\n ACTIONAREA: '.actions',\n ACTIVITYACTION: 'a.cm-edit-action',\n MENU: '.moodle-actionmenu[data-enhance=moodle-core-actionmenu]',\n TOGGLE: '.toggle-display,.dropdown-toggle',\n SECTIONLI: 'li.section',\n SECTIONACTIONMENU: '.section_action_menu',\n ADDSECTIONS: '.changenumsections [data-add-sections]'\n };\n\n Y.use('moodle-course-coursebase', function() {\n var courseformatselector = M.course.format.get_section_selector();\n if (courseformatselector) {\n SELECTOR.SECTIONLI = courseformatselector;\n }\n });\n\n /**\n * Dispatch event wrapper.\n *\n * Old jQuery events will be replaced by native events gradually.\n *\n * @method dispatchEvent\n * @param {String} eventName The name of the event\n * @param {Object} detail Any additional details to pass into the eveent\n * @param {Node|HTMLElement} container The point at which to dispatch the event\n * @param {Object} options\n * @param {Boolean} options.bubbles Whether to bubble up the DOM\n * @param {Boolean} options.cancelable Whether preventDefault() can be called\n * @param {Boolean} options.composed Whether the event can bubble across the ShadowDOM boundary\n * @returns {CustomEvent}\n */\n const dispatchEvent = function(eventName, detail, container, options) {\n // Most actions still uses jQuery node instead of regular HTMLElement.\n if (!(container instanceof Element) && container.get !== undefined) {\n container = container.get(0);\n }\n return EventDispatcher.dispatchEvent(eventName, detail, container, options);\n };\n\n /**\n * Wrapper for Y.Moodle.core_course.util.cm.getId\n *\n * @param {JQuery} element\n * @returns {Integer}\n */\n var getModuleId = function(element) {\n // Check if we have a data-id first.\n const item = element.get(0);\n if (item.dataset.id) {\n return item.dataset.id;\n }\n // Use YUI way if data-id is not present.\n let id;\n Y.use('moodle-course-util', function(Y) {\n id = Y.Moodle.core_course.util.cm.getId(Y.Node(item));\n });\n return id;\n };\n\n /**\n * Wrapper for Y.Moodle.core_course.util.cm.getName\n *\n * @param {JQuery} element\n * @returns {String}\n */\n var getModuleName = function(element) {\n var name;\n Y.use('moodle-course-util', function(Y) {\n name = Y.Moodle.core_course.util.cm.getName(Y.Node(element.get(0)));\n });\n // Check if we have the name in the course state.\n const state = courseeditor.state;\n const cmid = getModuleId(element);\n if (!name && state && cmid) {\n name = state.cm.get(cmid)?.name;\n }\n return name;\n };\n\n /**\n * Wrapper for M.util.add_spinner for an activity\n *\n * @param {JQuery} activity\n * @returns {Node}\n */\n var addActivitySpinner = function(activity) {\n activity.addClass(CSS.EDITINPROGRESS);\n var actionarea = activity.find(SELECTOR.ACTIONAREA).get(0);\n if (actionarea) {\n var spinner = M.util.add_spinner(Y, Y.Node(actionarea));\n spinner.show();\n // Lock the activity state element.\n if (activity.data('id') !== undefined) {\n courseeditor.dispatch('cmLock', [activity.data('id')], true);\n }\n return spinner;\n }\n return null;\n };\n\n /**\n * Wrapper for M.util.add_spinner for a section\n *\n * @param {JQuery} sectionelement\n * @returns {Node}\n */\n var addSectionSpinner = function(sectionelement) {\n sectionelement.addClass(CSS.EDITINPROGRESS);\n var actionarea = sectionelement.find(SELECTOR.SECTIONACTIONMENU).get(0);\n if (actionarea) {\n var spinner = M.util.add_spinner(Y, Y.Node(actionarea));\n spinner.show();\n // Lock the section state element.\n if (sectionelement.data('id') !== undefined) {\n courseeditor.dispatch('sectionLock', [sectionelement.data('id')], true);\n }\n return spinner;\n }\n return null;\n };\n\n /**\n * Wrapper for M.util.add_lightbox\n *\n * @param {JQuery} sectionelement\n * @returns {Node}\n */\n var addSectionLightbox = function(sectionelement) {\n var lightbox = M.util.add_lightbox(Y, Y.Node(sectionelement.get(0)));\n lightbox.show();\n return lightbox;\n };\n\n /**\n * Removes the spinner element\n *\n * @param {JQuery} element\n * @param {Node} spinner\n * @param {Number} delay\n */\n var removeSpinner = function(element, spinner, delay) {\n window.setTimeout(function() {\n element.removeClass(CSS.EDITINPROGRESS);\n if (spinner) {\n spinner.hide();\n }\n // Unlock the state element.\n if (element.data('id') !== undefined) {\n const mutation = (element.data('for') === 'section') ? 'sectionLock' : 'cmLock';\n courseeditor.dispatch(mutation, [element.data('id')], false);\n }\n }, delay);\n };\n\n /**\n * Removes the lightbox element\n *\n * @param {Node} lightbox lighbox YUI element returned by addSectionLightbox\n * @param {Number} delay\n */\n var removeLightbox = function(lightbox, delay) {\n if (lightbox) {\n window.setTimeout(function() {\n lightbox.hide();\n }, delay);\n }\n };\n\n /**\n * Initialise action menu for the element (section or module)\n *\n * @param {String} elementid CSS id attribute of the element\n */\n var initActionMenu = function(elementid) {\n // Initialise action menu in the new activity.\n Y.use('moodle-course-coursebase', function() {\n M.course.coursebase.invoke_function('setup_for_resource', '#' + elementid);\n });\n if (M.core.actionmenu && M.core.actionmenu.newDOMNode) {\n M.core.actionmenu.newDOMNode(Y.one('#' + elementid));\n }\n };\n\n /**\n * Returns focus to the element that was clicked or \"Edit\" link if element is no longer visible.\n *\n * @param {String} elementId CSS id attribute of the element\n * @param {String} action data-action property of the element that was clicked\n */\n var focusActionItem = function(elementId, action) {\n var mainelement = $('#' + elementId);\n var selector = '[data-action=' + action + ']';\n if (action === 'groupsseparate' || action === 'groupsvisible' || action === 'groupsnone') {\n // New element will have different data-action.\n selector = '[data-action=groupsseparate],[data-action=groupsvisible],[data-action=groupsnone]';\n }\n if (mainelement.find(selector).is(':visible')) {\n mainelement.find(selector).focus();\n } else {\n // Element not visible, focus the \"Edit\" link.\n mainelement.find(SELECTOR.MENU).find(SELECTOR.TOGGLE).focus();\n }\n };\n\n /**\n * Find next
after the element\n *\n * @param {JQuery} mainElement element that is about to be deleted\n * @returns {JQuery}\n */\n var findNextFocusable = function(mainElement) {\n var tabables = $(\"a:visible\");\n var isInside = false;\n var foundElement = null;\n tabables.each(function() {\n if ($.contains(mainElement[0], this)) {\n isInside = true;\n } else if (isInside) {\n foundElement = this;\n return false; // Returning false in .each() is equivalent to \"break;\" inside the loop in php.\n }\n return true;\n });\n return foundElement;\n };\n\n /**\n * Performs an action on a module (moving, deleting, duplicating, hiding, etc.)\n *\n * @param {JQuery} moduleElement activity element we perform action on\n * @param {Number} cmid\n * @param {JQuery} target the element (menu item) that was clicked\n */\n var editModule = function(moduleElement, cmid, target) {\n var action = target.attr('data-action');\n var spinner = addActivitySpinner(moduleElement);\n var promises = ajax.call([{\n methodname: 'core_course_edit_module',\n args: {id: cmid,\n action: action,\n sectionreturn: target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : 0\n }\n }], true);\n\n var lightbox;\n if (action === 'duplicate') {\n lightbox = addSectionLightbox(target.closest(SELECTOR.SECTIONLI));\n }\n $.when.apply($, promises)\n .done(function(data) {\n var elementToFocus = findNextFocusable(moduleElement);\n moduleElement.replaceWith(data);\n let affectedids = [];\n // Initialise action menu for activity(ies) added as a result of this.\n $('
' + data + '
').find(SELECTOR.ACTIVITYLI).each(function(index) {\n initActionMenu($(this).attr('id'));\n if (index === 0) {\n focusActionItem($(this).attr('id'), action);\n elementToFocus = null;\n }\n // Save any activity id in cmids.\n affectedids.push(getModuleId($(this)));\n });\n // In case of activity deletion focus the next focusable element.\n if (elementToFocus) {\n elementToFocus.focus();\n }\n // Remove spinner and lightbox with a delay.\n removeSpinner(moduleElement, spinner, 400);\n removeLightbox(lightbox, 400);\n // Trigger event that can be observed by course formats.\n moduleElement.trigger($.Event('coursemoduleedited', {ajaxreturn: data, action: action}));\n\n // Modify cm state.\n courseeditor.dispatch('legacyActivityAction', action, cmid, affectedids);\n\n }).fail(function(ex) {\n // Remove spinner and lightbox.\n removeSpinner(moduleElement, spinner);\n removeLightbox(lightbox);\n // Trigger event that can be observed by course formats.\n var e = $.Event('coursemoduleeditfailed', {exception: ex, action: action});\n moduleElement.trigger(e);\n if (!e.isDefaultPrevented()) {\n notification.exception(ex);\n }\n });\n };\n\n /**\n * Requests html for the module via WS core_course_get_module and updates the module on the course page\n *\n * Used after d&d of the module to another section\n *\n * @param {JQuery|Element} element\n * @param {Number} cmid\n * @param {Number} sectionreturn\n * @return {Promise} the refresh promise\n */\n var refreshModule = function(element, cmid, sectionreturn) {\n\n if (sectionreturn === undefined) {\n sectionreturn = courseeditor.sectionReturn;\n }\n\n const activityElement = $(element);\n var spinner = addActivitySpinner(activityElement);\n var promises = ajax.call([{\n methodname: 'core_course_get_module',\n args: {id: cmid, sectionreturn: sectionreturn}\n }], true);\n\n return new Promise((resolve, reject) => {\n $.when.apply($, promises)\n .done(function(data) {\n removeSpinner(activityElement, spinner, 400);\n replaceActivityHtmlWith(data);\n resolve(data);\n }).fail(function() {\n removeSpinner(activityElement, spinner);\n reject();\n });\n });\n };\n\n /**\n * Requests html for the section via WS core_course_edit_section and updates the section on the course page\n *\n * @param {JQuery|Element} element\n * @param {Number} sectionid\n * @param {Number} sectionreturn\n * @return {Promise} the refresh promise\n */\n var refreshSection = function(element, sectionid, sectionreturn) {\n\n if (sectionreturn === undefined) {\n sectionreturn = courseeditor.sectionReturn;\n }\n\n const sectionElement = $(element);\n const action = 'refresh';\n const promises = ajax.call([{\n methodname: 'core_course_edit_section',\n args: {id: sectionid, action, sectionreturn},\n }], true);\n\n var spinner = addSectionSpinner(sectionElement);\n return new Promise((resolve, reject) => {\n $.when.apply($, promises)\n .done(dataencoded => {\n\n removeSpinner(sectionElement, spinner);\n const data = $.parseJSON(dataencoded);\n\n const newSectionElement = $(data.content);\n sectionElement.replaceWith(newSectionElement);\n\n // Init modules menus.\n $(`${SELECTOR.SECTIONLI}#${sectionid} ${SELECTOR.ACTIVITYLI}`).each(\n (index, activity) => {\n initActionMenu(activity.data('id'));\n }\n );\n\n // Trigger event that can be observed by course formats.\n const event = dispatchEvent(\n CourseEvents.sectionRefreshed,\n {\n ajaxreturn: data,\n action: action,\n newSectionElement: newSectionElement.get(0),\n },\n newSectionElement\n );\n\n if (!event.defaultPrevented) {\n defaultEditSectionHandler(\n newSectionElement, $(SELECTOR.SECTIONLI + '#' + sectionid),\n data,\n formatname,\n sectionid\n );\n }\n resolve(data);\n }).fail(ex => {\n // Trigger event that can be observed by course formats.\n const event = dispatchEvent(\n 'coursesectionrefreshfailed',\n {exception: ex, action: action},\n sectionElement\n );\n if (!event.defaultPrevented) {\n notification.exception(ex);\n }\n reject();\n });\n });\n };\n\n /**\n * Displays the delete confirmation to delete a module\n *\n * @param {JQuery} mainelement activity element we perform action on\n * @param {function} onconfirm function to execute on confirm\n */\n var confirmDeleteModule = function(mainelement, onconfirm) {\n var modtypename = mainelement.attr('class').match(/modtype_([^\\s]*)/)[1];\n var modulename = getModuleName(mainelement);\n\n str.get_string('pluginname', modtypename).done(function(pluginname) {\n var plugindata = {\n type: pluginname,\n name: modulename\n };\n str.get_strings([\n {key: 'confirm', component: 'core'},\n {key: modulename === null ? 'deletechecktype' : 'deletechecktypename', param: plugindata},\n {key: 'yes'},\n {key: 'no'}\n ]).done(function(s) {\n notification.confirm(s[0], s[1], s[2], s[3], onconfirm);\n }\n );\n });\n };\n\n /**\n * Displays the delete confirmation to delete a section\n *\n * @param {String} message confirmation message\n * @param {function} onconfirm function to execute on confirm\n */\n var confirmEditSection = function(message, onconfirm) {\n str.get_strings([\n {key: 'confirm'}, // TODO link text\n {key: 'yes'},\n {key: 'no'}\n ]).done(function(s) {\n notification.confirm(s[0], message, s[1], s[2], onconfirm);\n }\n );\n };\n\n /**\n * Replaces an action menu item with another one (for example Show->Hide, Set marker->Remove marker)\n *\n * @param {JQuery} actionitem\n * @param {String} image new image name (\"i/show\", \"i/hide\", etc.)\n * @param {String} stringname new string for the action menu item\n * @param {String} stringcomponent\n * @param {String} newaction new value for data-action attribute of the link\n * @return {Promise} promise which is resolved when the replacement has completed\n */\n var replaceActionItem = function(actionitem, image, stringname,\n stringcomponent, newaction) {\n\n var stringRequests = [{key: stringname, component: stringcomponent}];\n // Do not provide an icon with duplicate, different text to the menu item.\n\n return str.get_strings(stringRequests).then(function(strings) {\n actionitem.find('span.menu-action-text').html(strings[0]);\n\n return templates.renderPix(image, 'core');\n }).then(function(pixhtml) {\n actionitem.find('.icon').replaceWith(pixhtml);\n actionitem.attr('data-action', newaction);\n return;\n }).catch(notification.exception);\n };\n\n /**\n * Default post-processing for section AJAX edit actions.\n *\n * This can be overridden in course formats by listening to event coursesectionedited:\n *\n * $('body').on('coursesectionedited', 'li.section', function(e) {\n * var action = e.action,\n * sectionElement = $(e.target),\n * data = e.ajaxreturn;\n * // ... Do some processing here.\n * e.preventDefault(); // Prevent default handler.\n * });\n *\n * @param {JQuery} sectionElement\n * @param {JQuery} actionItem\n * @param {Object} data\n * @param {String} courseformat\n * @param {Number} sectionid\n */\n var defaultEditSectionHandler = function(sectionElement, actionItem, data, courseformat, sectionid) {\n var action = actionItem.attr('data-action');\n if (action === 'hide' || action === 'show') {\n if (action === 'hide') {\n sectionElement.addClass('hidden');\n replaceActionItem(actionItem, 'i/show',\n 'showfromothers', 'format_' + courseformat, 'show');\n } else {\n sectionElement.removeClass('hidden');\n replaceActionItem(actionItem, 'i/hide',\n 'hidefromothers', 'format_' + courseformat, 'hide');\n }\n // Replace the modules with new html (that indicates that they are now hidden or not hidden).\n if (data.modules !== undefined) {\n for (var i in data.modules) {\n replaceActivityHtmlWith(data.modules[i]);\n }\n }\n // Replace the section availability information.\n if (data.section_availability !== undefined) {\n sectionElement.find('.section_availability').first().replaceWith(data.section_availability);\n }\n // Modify course state.\n const section = courseeditor.state.section.get(sectionid);\n if (section !== undefined) {\n courseeditor.dispatch('sectionState', [sectionid]);\n }\n } else if (action === 'setmarker') {\n var oldmarker = $(SELECTOR.SECTIONLI + '.current'),\n oldActionItem = oldmarker.find(SELECTOR.SECTIONACTIONMENU + ' ' + 'a[data-action=removemarker]');\n oldmarker.removeClass('current');\n replaceActionItem(oldActionItem, 'i/marker',\n 'highlight', 'core', 'setmarker');\n sectionElement.addClass('current');\n replaceActionItem(actionItem, 'i/marked',\n 'highlightoff', 'core', 'removemarker');\n courseeditor.dispatch('legacySectionAction', action, sectionid);\n } else if (action === 'removemarker') {\n sectionElement.removeClass('current');\n replaceActionItem(actionItem, 'i/marker',\n 'highlight', 'core', 'setmarker');\n courseeditor.dispatch('legacySectionAction', action, sectionid);\n }\n };\n\n /**\n * Get the focused element path in an activity if any.\n *\n * This method is used to restore focus when the activity HTML is refreshed.\n * Only the main course editor elements can be refocused as they are always present\n * even if the activity content changes.\n *\n * @param {String} id the element id the activity element\n * @return {String|undefined} the inner path of the focused element or undefined\n */\n const getActivityFocusedElement = function(id) {\n const element = document.getElementById(id);\n if (!element || !element.contains(document.activeElement)) {\n return undefined;\n }\n // Check if the actions menu toggler is focused.\n if (element.querySelector(SELECTOR.ACTIONAREA).contains(document.activeElement)) {\n return `${SELECTOR.ACTIONAREA} [tabindex=\"0\"]`;\n }\n // Return the current element id if any.\n if (document.activeElement.id) {\n return `#${document.activeElement.id}`;\n }\n return undefined;\n };\n\n /**\n * Replaces the course module with the new html (used to update module after it was edited or its visibility was changed).\n *\n * @param {String} activityHTML\n */\n var replaceActivityHtmlWith = function(activityHTML) {\n $('
' + activityHTML + '
').find(SELECTOR.ACTIVITYLI).each(function() {\n // Extract id from the new activity html.\n var id = $(this).attr('id');\n // Check if the current focused element is inside the activity.\n let focusedPath = getActivityFocusedElement(id);\n // Find the existing element with the same id and replace its contents with new html.\n $(SELECTOR.ACTIVITYLI + '#' + id).replaceWith(activityHTML);\n // Initialise action menu.\n initActionMenu(id);\n // Re-focus the previous elements.\n if (focusedPath) {\n const newItem = document.getElementById(id);\n newItem.querySelector(focusedPath)?.focus();\n }\n\n });\n };\n\n /**\n * Performs an action on a module (moving, deleting, duplicating, hiding, etc.)\n *\n * @param {JQuery} sectionElement section element we perform action on\n * @param {Nunmber} sectionid\n * @param {JQuery} target the element (menu item) that was clicked\n * @param {String} courseformat\n * @return {boolean} true the action call is sent to the server or false if it is ignored.\n */\n var editSection = function(sectionElement, sectionid, target, courseformat) {\n var action = target.attr('data-action'),\n sectionreturn = target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : 0;\n\n // Filter direct component handled actions.\n if (courseeditor.supportComponents && componentActions.includes(action)) {\n return false;\n }\n\n var spinner = addSectionSpinner(sectionElement);\n var promises = ajax.call([{\n methodname: 'core_course_edit_section',\n args: {id: sectionid, action: action, sectionreturn: sectionreturn}\n }], true);\n\n var lightbox = addSectionLightbox(sectionElement);\n $.when.apply($, promises)\n .done(function(dataencoded) {\n var data = $.parseJSON(dataencoded);\n removeSpinner(sectionElement, spinner);\n removeLightbox(lightbox);\n sectionElement.find(SELECTOR.SECTIONACTIONMENU).find(SELECTOR.TOGGLE).focus();\n // Trigger event that can be observed by course formats.\n var e = $.Event('coursesectionedited', {ajaxreturn: data, action: action});\n sectionElement.trigger(e);\n if (!e.isDefaultPrevented()) {\n defaultEditSectionHandler(sectionElement, target, data, courseformat, sectionid);\n }\n }).fail(function(ex) {\n // Remove spinner and lightbox.\n removeSpinner(sectionElement, spinner);\n removeLightbox(lightbox);\n // Trigger event that can be observed by course formats.\n var e = $.Event('coursesectioneditfailed', {exception: ex, action: action});\n sectionElement.trigger(e);\n if (!e.isDefaultPrevented()) {\n notification.exception(ex);\n }\n });\n return true;\n };\n\n // Register a function to be executed after D&D of an activity.\n Y.use('moodle-course-coursebase', function() {\n M.course.coursebase.register_module({\n // Ignore camelcase eslint rule for the next line because it is an expected name of the callback.\n // eslint-disable-next-line camelcase\n set_visibility_resource_ui: function(args) {\n var mainelement = $(args.element.getDOMNode());\n var cmid = getModuleId(mainelement);\n if (cmid) {\n var sectionreturn = mainelement.find('.' + CSS.EDITINGMOVE).attr('data-sectionreturn');\n refreshModule(mainelement, cmid, sectionreturn);\n }\n },\n /**\n * Update the course state when some cm is moved via YUI.\n * @param {*} params\n */\n updateMovedCmState: (params) => {\n const state = courseeditor.state;\n\n // Update old section.\n const cm = state.cm.get(params.cmid);\n if (cm !== undefined) {\n courseeditor.dispatch('sectionState', [cm.sectionid]);\n }\n // Update cm state.\n courseeditor.dispatch('cmState', [params.cmid]);\n },\n /**\n * Update the course state when some section is moved via YUI.\n */\n updateMovedSectionState: () => {\n courseeditor.dispatch('courseState');\n },\n });\n });\n\n // From Moodle 4.0 all edit actions are being re-implemented as state mutation.\n // This means all method from this \"actions\" module will be deprecated when all the course\n // interface is migrated to reactive components.\n // Most legacy actions did not provide enough information to regenarate the course so they\n // use the mutations courseState, sectionState and cmState to get the updated state from\n // the server. However, some activity actions where we can prevent an extra webservice\n // call by implementing an adhoc mutation.\n courseeditor.addMutations({\n /**\n * Compatibility function to update Moodle 4.0 course state using legacy actions.\n *\n * This method only updates some actions which does not require to use cmState mutation\n * to get updated data form the server.\n *\n * @param {Object} statemanager the current state in read write mode\n * @param {String} action the performed action\n * @param {Number} cmid the affected course module id\n * @param {Array} affectedids all affected cm ids (for duplicate action)\n */\n legacyActivityAction: function(statemanager, action, cmid, affectedids) {\n\n const state = statemanager.state;\n const cm = state.cm.get(cmid);\n if (cm === undefined) {\n return;\n }\n const section = state.section.get(cm.sectionid);\n if (section === undefined) {\n return;\n }\n\n // Send the element is locked. Reactive events are only triggered when the state\n // read only mode is restored. We want to notify the interface the element is\n // locked so we need to do a quick lock operation before performing the rest\n // of the mutation.\n statemanager.setReadOnly(false);\n cm.locked = true;\n statemanager.setReadOnly(true);\n\n // Now we do the real mutation.\n statemanager.setReadOnly(false);\n\n // This locked will take effect when the read only is restored.\n cm.locked = false;\n\n switch (action) {\n case 'delete':\n // Remove from section.\n section.cmlist = section.cmlist.reduce(\n (cmlist, current) => {\n if (current != cmid) {\n cmlist.push(current);\n }\n return cmlist;\n },\n []\n );\n // Delete form list.\n state.cm.delete(cmid);\n break;\n\n case 'hide':\n case 'show':\n cm.visible = (action === 'show') ? true : false;\n break;\n\n case 'duplicate':\n // Duplicate requires to get extra data from the server.\n courseeditor.dispatch('cmState', affectedids);\n break;\n }\n statemanager.setReadOnly(true);\n },\n legacySectionAction: function(statemanager, action, sectionid) {\n\n const state = statemanager.state;\n const section = state.section.get(sectionid);\n if (section === undefined) {\n return;\n }\n\n // Send the element is locked. Reactive events are only triggered when the state\n // read only mode is restored. We want to notify the interface the element is\n // locked so we need to do a quick lock operation before performing the rest\n // of the mutation.\n statemanager.setReadOnly(false);\n section.locked = true;\n statemanager.setReadOnly(true);\n\n // Now we do the real mutation.\n statemanager.setReadOnly(false);\n\n // This locked will take effect when the read only is restored.\n section.locked = false;\n\n switch (action) {\n case 'setmarker':\n // Remove previous marker.\n state.section.forEach((current) => {\n if (current.id != sectionid) {\n current.current = false;\n }\n });\n section.current = true;\n break;\n\n case 'removemarker':\n section.current = false;\n break;\n }\n statemanager.setReadOnly(true);\n },\n });\n\n return /** @alias module:core_course/actions */ {\n\n /**\n * Initialises course page\n *\n * @method init\n * @param {String} courseformat name of the current course format (for fetching strings)\n */\n initCoursePage: function(courseformat) {\n\n formatname = courseformat;\n\n // Add a handler for course module actions.\n $('body').on('click keypress', SELECTOR.ACTIVITYLI + ' ' +\n SELECTOR.ACTIVITYACTION + '[data-action]', function(e) {\n if (e.type === 'keypress' && e.keyCode !== 13) {\n return;\n }\n var actionItem = $(this),\n moduleElement = actionItem.closest(SELECTOR.ACTIVITYLI),\n action = actionItem.attr('data-action'),\n moduleId = getModuleId(moduleElement);\n switch (action) {\n case 'moveleft':\n case 'moveright':\n case 'delete':\n case 'duplicate':\n case 'hide':\n case 'stealth':\n case 'show':\n case 'groupsseparate':\n case 'groupsvisible':\n case 'groupsnone':\n break;\n default:\n // Nothing to do here!\n return;\n }\n if (!moduleId) {\n return;\n }\n e.preventDefault();\n if (action === 'delete') {\n // Deleting requires confirmation.\n confirmDeleteModule(moduleElement, function() {\n editModule(moduleElement, moduleId, actionItem);\n });\n } else {\n editModule(moduleElement, moduleId, actionItem);\n }\n });\n\n // Add a handler for section show/hide actions.\n $('body').on('click keypress', SELECTOR.SECTIONLI + ' ' +\n SELECTOR.SECTIONACTIONMENU + '[data-sectionid] ' +\n 'a[data-action]', function(e) {\n if (e.type === 'keypress' && e.keyCode !== 13) {\n return;\n }\n var actionItem = $(this),\n sectionElement = actionItem.closest(SELECTOR.SECTIONLI),\n sectionId = actionItem.closest(SELECTOR.SECTIONACTIONMENU).attr('data-sectionid');\n\n let isExecuted = true;\n if (actionItem.attr('data-confirm')) {\n // Action requires confirmation.\n confirmEditSection(actionItem.attr('data-confirm'), function() {\n isExecuted = editSection(sectionElement, sectionId, actionItem, courseformat);\n });\n } else {\n isExecuted = editSection(sectionElement, sectionId, actionItem, courseformat);\n }\n // Prevent any other module from capturing the action if it is already in execution.\n if (isExecuted) {\n e.preventDefault();\n }\n });\n\n // The section and activity names are edited using inplace editable.\n // The \"update\" jQuery event must be captured in order to update the course state.\n $('body').on('updated', `${SELECTOR.SECTIONLI} [data-inplaceeditable]`, function(e) {\n if (e.ajaxreturn && e.ajaxreturn.itemid) {\n const state = courseeditor.state;\n const section = state.section.get(e.ajaxreturn.itemid);\n if (section !== undefined) {\n courseeditor.dispatch('sectionState', [e.ajaxreturn.itemid]);\n }\n }\n });\n $('body').on('updated', `${SELECTOR.ACTIVITYLI} [data-inplaceeditable]`, function(e) {\n if (e.ajaxreturn && e.ajaxreturn.itemid) {\n courseeditor.dispatch('cmState', [e.ajaxreturn.itemid]);\n }\n });\n\n // Component-based formats don't use modals to create sections.\n if (courseeditor.supportComponents && componentActions.includes('addSection')) {\n return;\n }\n\n // Add a handler for \"Add sections\" link to ask for a number of sections to add.\n str.get_string('numberweeks').done(function(strNumberSections) {\n var trigger = $(SELECTOR.ADDSECTIONS),\n modalTitle = trigger.attr('data-add-sections'),\n newSections = trigger.attr('data-new-sections');\n var modalBody = $('
' +\n '
');\n modalBody.find('label').html(strNumberSections);\n ModalFactory.create({\n title: modalTitle,\n type: ModalFactory.types.SAVE_CANCEL,\n body: modalBody.html()\n }, trigger)\n .done(function(modal) {\n var numSections = $(modal.getBody()).find('#add_section_numsections'),\n addSections = function() {\n // Check if value of the \"Number of sections\" is a valid positive integer and redirect\n // to adding a section script.\n if ('' + parseInt(numSections.val()) === numSections.val() && parseInt(numSections.val()) >= 1) {\n document.location = trigger.attr('href') + '&numsections=' + parseInt(numSections.val());\n }\n };\n modal.setSaveButtonText(modalTitle);\n modal.getRoot().on(ModalEvents.shown, function() {\n // When modal is shown focus and select the input and add a listener to keypress of \"Enter\".\n numSections.focus().select().on('keydown', function(e) {\n if (e.keyCode === KeyCodes.enter) {\n addSections();\n }\n });\n });\n modal.getRoot().on(ModalEvents.save, function(e) {\n // When modal \"Add\" button is pressed.\n e.preventDefault();\n addSections();\n });\n });\n });\n },\n\n /**\n * Replaces a section action menu item with another one (for example Show->Hide, Set marker->Remove marker)\n *\n * This method can be used by course formats in their listener to the coursesectionedited event\n *\n * @deprecated since Moodle 3.9\n * @param {JQuery} sectionelement\n * @param {String} selector CSS selector inside the section element, for example \"a[data-action=show]\"\n * @param {String} image new image name (\"i/show\", \"i/hide\", etc.)\n * @param {String} stringname new string for the action menu item\n * @param {String} stringcomponent\n * @param {String} newaction new value for data-action attribute of the link\n */\n replaceSectionActionItem: function(sectionelement, selector, image, stringname,\n stringcomponent, newaction) {\n log.debug('replaceSectionActionItem() is deprecated and will be removed.');\n var actionitem = sectionelement.find(SELECTOR.SECTIONACTIONMENU + ' ' + selector);\n replaceActionItem(actionitem, image, stringname, stringcomponent, newaction);\n },\n // Method to refresh a module.\n refreshModule,\n refreshSection,\n };\n });\n"],"file":"actions.min.js"} \ No newline at end of file diff --git a/course/amd/src/actions.js b/course/amd/src/actions.js index 1742aa0c85c..491cde1e462 100644 --- a/course/amd/src/actions.js +++ b/course/amd/src/actions.js @@ -607,6 +607,32 @@ define( } }; + /** + * Get the focused element path in an activity if any. + * + * This method is used to restore focus when the activity HTML is refreshed. + * Only the main course editor elements can be refocused as they are always present + * even if the activity content changes. + * + * @param {String} id the element id the activity element + * @return {String|undefined} the inner path of the focused element or undefined + */ + const getActivityFocusedElement = function(id) { + const element = document.getElementById(id); + if (!element || !element.contains(document.activeElement)) { + return undefined; + } + // Check if the actions menu toggler is focused. + if (element.querySelector(SELECTOR.ACTIONAREA).contains(document.activeElement)) { + return `${SELECTOR.ACTIONAREA} [tabindex="0"]`; + } + // Return the current element id if any. + if (document.activeElement.id) { + return `#${document.activeElement.id}`; + } + return undefined; + }; + /** * Replaces the course module with the new html (used to update module after it was edited or its visibility was changed). * @@ -616,10 +642,18 @@ define( $('
' + activityHTML + '
').find(SELECTOR.ACTIVITYLI).each(function() { // Extract id from the new activity html. var id = $(this).attr('id'); + // Check if the current focused element is inside the activity. + let focusedPath = getActivityFocusedElement(id); // Find the existing element with the same id and replace its contents with new html. $(SELECTOR.ACTIVITYLI + '#' + id).replaceWith(activityHTML); // Initialise action menu. initActionMenu(id); + // Re-focus the previous elements. + if (focusedPath) { + const newItem = document.getElementById(id); + newItem.querySelector(focusedPath)?.focus(); + } + }); }; diff --git a/course/format/amd/build/local/content/actions.min.js b/course/format/amd/build/local/content/actions.min.js index cca5dcbafd8..d0acaf23ce9 100644 --- a/course/format/amd/build/local/content/actions.min.js +++ b/course/format/amd/build/local/content/actions.min.js @@ -1,2 +1,2 @@ -define ("core_courseformat/local/content/actions",["exports","core/reactive","core/modal_factory","core/modal_events","core/templates","core/prefetch","core/str","core/normalise","core_course/events"],function(a,b,c,d,e,f,g,h,i){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;c=l(c);d=l(d);e=l(e);i=k(i);function j(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;j=function(){return a};return a}function k(a){if(a&&a.__esModule){return a}if(null===a||"object"!==m(a)&&"function"!=typeof a){return{default:a}}var b=j();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function l(a){return a&&a.__esModule?a:{default:a}}function m(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){m=function(a){return typeof a}}else{m=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return m(a)}function n(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function o(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){n(h,d,e,f,g,"next",a)}function g(a){n(h,d,e,f,g,"throw",a)}f(void 0)})}}function p(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function q(a,b){for(var c=0,d;cb.course.maxsections)}},{key:"_requestMoveSection",value:function(){var a=o(regeneratorRuntime.mark(function a(b,c){var d=this,f,i,j,k,l,m,n,o,p;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:f=b.dataset.id;if(f){a.next=3;break}return a.abrupt("return");case 3:i=this.reactive.get("section",f);c.preventDefault();j=this.reactive.getExporter();k=j.course(this.reactive.state);k.sectionid=i.id;k.sectiontitle=i.title;l={title:(0,g.get_string)("movecoursesection","core"),body:e.default.render("core_courseformat/local/content/movesection",k)};a.next=12;return this._modalBodyRenderedPromise(l);case 12:m=a.sent;n=(0,h.getList)(m.getBody())[0];o=n.querySelector("".concat(this.selectors.SECTIONLINK,"[data-id='").concat(f,"']"));this._disableLink(o);p=n.querySelector("".concat(this.selectors.SECTIONLINK,"[data-number='0']"));this._disableLink(p);n.addEventListener("click",function(a){var b=a.target;if(!b.matches("a")||"section"!=b.dataset.for||b.dataset.id===void 0){return}if(b.getAttribute("aria-disabled")){return}a.preventDefault();d.reactive.dispatch("sectionMove",[f],b.dataset.id);m.destroy()});case 19:case"end":return a.stop();}}},a,this)}));return function _requestMoveSection(){return a.apply(this,arguments)}}()},{key:"_requestMoveCm",value:function(){var a=o(regeneratorRuntime.mark(function a(b,c){var d,f,i=this,j,k,l,m,n,o,p,q;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:j=b.dataset.id;if(j){a.next=3;break}return a.abrupt("return");case 3:k=this.reactive.get("cm",j);c.preventDefault();l=this.reactive.getExporter();m=l.course(this.reactive.state);m.cmid=k.id;m.cmname=k.name;n={title:(0,g.get_string)("movecoursemodule","core"),body:e.default.render("core_courseformat/local/content/movecm",m)};a.next=12;return this._modalBodyRenderedPromise(n);case 12:o=a.sent;p=(0,h.getList)(o.getBody())[0];q=p.querySelector("".concat(this.selectors.CMLINK,"[data-id='").concat(j,"']"));this._disableLink(q);null===(d=q.closest(this.selectors.SECTIONNODE))||void 0===d?void 0:null===(f=d.querySelector(this.selectors.TOGGLER))||void 0===f?void 0:f.click();p.addEventListener("click",function(a){var b=a.target;if(!b.matches("a")||b.dataset.for===void 0||b.dataset.id===void 0){return}if(b.getAttribute("aria-disabled")){return}a.preventDefault();var c,d;if("cm"==b.dataset.for){var e=l.cmDraggableData(i.reactive.state,b.dataset.id);c=e.sectionid;d=e.nextcmid}else{var f=i.reactive.get("section",b.dataset.id);c=b.dataset.id;d=null===f||void 0===f?void 0:f.cmlist[0]}i.reactive.dispatch("cmMove",[j],c,d);o.destroy()});case 18:case"end":return a.stop();}}},a,this)}));return function _requestMoveCm(){return a.apply(this,arguments)}}()},{key:"_requestAddSection",value:function(){var a=o(regeneratorRuntime.mark(function a(b,c){var d;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:c.preventDefault();this.reactive.dispatch("addSection",null!==(d=b.dataset.id)&&void 0!==d?d:0);case 2:case"end":return a.stop();}}},a,this)}));return function _requestAddSection(){return a.apply(this,arguments)}}()},{key:"_requestDeleteSection",value:function(){var a=o(regeneratorRuntime.mark(function a(b,e){var f,h=this,i,j,k,l,m;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:i=b.dataset.id;if(i){a.next=3;break}return a.abrupt("return");case 3:j=this.reactive.get("section",i);e.preventDefault();k=null!==(f=j.cmlist)&&void 0!==f?f:[];if(!(k.length||j.hassummary||j.rawtitle)){a.next=15;break}l={title:(0,g.get_string)("confirm","core"),body:(0,g.get_string)("confirmdeletesection","moodle",j.title),saveButtonText:(0,g.get_string)("delete","core"),type:c.default.types.SAVE_CANCEL};a.next=10;return this._modalBodyRenderedPromise(l);case 10:m=a.sent;m.getRoot().on(d.default.save,function(a){a.preventDefault();m.destroy();h.reactive.dispatch("sectionDelete",[i])});return a.abrupt("return");case 15:this.reactive.dispatch("sectionDelete",[i]);case 16:case"end":return a.stop();}}},a,this)}));return function _requestDeleteSection(){return a.apply(this,arguments)}}()},{key:"_setAddSectionLocked",value:function _setAddSectionLocked(a){var b=this,c=this.getElements(this.selectors.ADDSECTION);c.forEach(function(c){c.classList.toggle(b.classes.DISABLED,a);b.setElementLocked(c,a)})}},{key:"_disableLink",value:function _disableLink(a){if(a){a.style.pointerEvents="none";a.style.userSelect="none";a.classList.add(this.classes.DISABLED);a.setAttribute("aria-disabled",!0);a.addEventListener("click",function(a){return a.preventDefault()})}}},{key:"_modalBodyRenderedPromise",value:function _modalBodyRenderedPromise(a){return new Promise(function(b,e){c.default.create(a).then(function(c){c.getRoot().on(d.default.bodyRendered,function(){b(c)});if(a.saveButtonText!==void 0){c.setSaveButtonText(a.saveButtonText)}c.show()}).catch(function(){e("Cannot load modal content")})})}}]);return b}(b.BaseComponent);a.default=z;return a.default}); +define ("core_courseformat/local/content/actions",["exports","core/reactive","core/modal_factory","core/modal_events","core/templates","core/prefetch","core/str","core/normalise","core_course/events","core/pending","core_courseformat/local/courseeditor/contenttree","jquery"],function(a,b,c,d,e,f,g,h,i,j,k,l){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;c=o(c);d=o(d);e=o(e);i=n(i);j=o(j);k=o(k);l=o(l);function m(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;m=function(){return a};return a}function n(a){if(a&&a.__esModule){return a}if(null===a||"object"!==p(a)&&"function"!=typeof a){return{default:a}}var b=m();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function o(a){return a&&a.__esModule?a:{default:a}}function p(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){p=function(a){return typeof a}}else{p=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return p(a)}function q(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function r(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){q(h,d,e,f,g,"next",a)}function g(a){q(h,d,e,f,g,"throw",a)}f(void 0)})}}function s(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function t(a,b){for(var c=0,d;cb.course.maxsections)}},{key:"_requestMoveSection",value:function(){var a=r(regeneratorRuntime.mark(function a(b,c){var d=this,f,i,j,l,m,n,o,p,q,r;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:f=b.dataset.id;if(f){a.next=3;break}return a.abrupt("return");case 3:i=this.reactive.get("section",f);c.preventDefault();j=this._getClosestActionMenuToogler(b);l=this.reactive.getExporter();m=l.course(this.reactive.state);m.sectionid=i.id;m.sectiontitle=i.title;n={title:(0,g.get_string)("movecoursesection","core"),body:e.default.render("core_courseformat/local/content/movesection",m)};a.next=13;return this._modalBodyRenderedPromise(n);case 13:o=a.sent;p=(0,h.getList)(o.getBody())[0];q=p.querySelector("".concat(this.selectors.SECTIONLINK,"[data-id='").concat(f,"']"));this._disableLink(q);r=p.querySelector("".concat(this.selectors.SECTIONLINK,"[data-number='0']"));this._disableLink(r);new k.default(p.querySelector(this.selectors.CONTENTTREE),{SECTION:this.selectors.SECTIONNODE,TOGGLER:this.selectors.MODALTOGGLER,COLLAPSE:this.selectors.MODALTOGGLER},!0);p.addEventListener("click",function(a){var b=a.target;if(!b.matches("a")||"section"!=b.dataset.for||b.dataset.id===void 0){return}if(b.getAttribute("aria-disabled")){return}a.preventDefault();d.reactive.dispatch("sectionMove",[f],b.dataset.id);d._destroyModal(o,j)});case 21:case"end":return a.stop();}}},a,this)}));return function _requestMoveSection(){return a.apply(this,arguments)}}()},{key:"_requestMoveCm",value:function(){var a=r(regeneratorRuntime.mark(function a(b,c){var d,f=this,i,j,m,n,o,p,q,r,s,t,u,v;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:i=b.dataset.id;if(i){a.next=3;break}return a.abrupt("return");case 3:j=this.reactive.get("cm",i);c.preventDefault();m=this._getClosestActionMenuToogler(b);n=this.reactive.getExporter();o=n.course(this.reactive.state);o.cmid=j.id;o.cmname=j.name;p={title:(0,g.get_string)("movecoursemodule","core"),body:e.default.render("core_courseformat/local/content/movecm",o)};a.next=13;return this._modalBodyRenderedPromise(p);case 13:q=a.sent;r=(0,h.getList)(q.getBody())[0];s=r.querySelector("".concat(this.selectors.CMLINK,"[data-id='").concat(i,"']"));this._disableLink(s);new k.default(r.querySelector(this.selectors.CONTENTTREE),{SECTION:this.selectors.SECTIONNODE,TOGGLER:this.selectors.MODALTOGGLER,COLLAPSE:this.selectors.MODALTOGGLER,ENTER:this.selectors.SECTIONLINK});t=s.closest(this.selectors.SECTIONNODE);u=(0,l.default)(t).find(this.selectors.MODALTOGGLER);v=null!==(d=u.data("target"))&&void 0!==d?d:u.attr("href");if(v){v=v.replace("#","");(0,l.default)("#".concat(v)).collapse("toggle")}r.addEventListener("click",function(a){var b=a.target;if(!b.matches("a")||b.dataset.for===void 0||b.dataset.id===void 0){return}if(b.getAttribute("aria-disabled")){return}a.preventDefault();var c,d;if("cm"==b.dataset.for){var e=n.cmDraggableData(f.reactive.state,b.dataset.id);c=e.sectionid;d=e.nextcmid}else{var g=f.reactive.get("section",b.dataset.id);c=b.dataset.id;d=null===g||void 0===g?void 0:g.cmlist[0]}f.reactive.dispatch("cmMove",[i],c,d);f._destroyModal(q,m)});case 23:case"end":return a.stop();}}},a,this)}));return function _requestMoveCm(){return a.apply(this,arguments)}}()},{key:"_requestAddSection",value:function(){var a=r(regeneratorRuntime.mark(function a(b,c){var d;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:c.preventDefault();this.reactive.dispatch("addSection",null!==(d=b.dataset.id)&&void 0!==d?d:0);case 2:case"end":return a.stop();}}},a,this)}));return function _requestAddSection(){return a.apply(this,arguments)}}()},{key:"_requestDeleteSection",value:function(){var a=r(regeneratorRuntime.mark(function a(b,e){var f,h=this,i,j,k,l,m;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:i=b.dataset.id;if(i){a.next=3;break}return a.abrupt("return");case 3:j=this.reactive.get("section",i);e.preventDefault();k=null!==(f=j.cmlist)&&void 0!==f?f:[];if(!(k.length||j.hassummary||j.rawtitle)){a.next=15;break}l={title:(0,g.get_string)("confirm","core"),body:(0,g.get_string)("confirmdeletesection","moodle",j.title),saveButtonText:(0,g.get_string)("delete","core"),type:c.default.types.SAVE_CANCEL};a.next=10;return this._modalBodyRenderedPromise(l);case 10:m=a.sent;m.getRoot().on(d.default.save,function(a){a.preventDefault();m.destroy();h.reactive.dispatch("sectionDelete",[i])});return a.abrupt("return");case 15:this.reactive.dispatch("sectionDelete",[i]);case 16:case"end":return a.stop();}}},a,this)}));return function _requestDeleteSection(){return a.apply(this,arguments)}}()},{key:"_setAddSectionLocked",value:function _setAddSectionLocked(a){var b=this,c=this.getElements(this.selectors.ADDSECTION);c.forEach(function(c){c.classList.toggle(b.classes.DISABLED,a);b.setElementLocked(c,a)})}},{key:"_disableLink",value:function _disableLink(a){if(a){a.style.pointerEvents="none";a.style.userSelect="none";a.classList.add(this.classes.DISABLED);a.setAttribute("aria-disabled",!0);a.addEventListener("click",function(a){return a.preventDefault()})}}},{key:"_modalBodyRenderedPromise",value:function _modalBodyRenderedPromise(a){return new Promise(function(b,e){c.default.create(a).then(function(c){c.setRemoveOnClose(!0);c.getRoot().on(d.default.bodyRendered,function(){b(c)});if(a.saveButtonText!==void 0){c.setSaveButtonText(a.saveButtonText)}c.show()}).catch(function(){e("Cannot load modal content")})})}},{key:"_destroyModal",value:function _destroyModal(a,b){a.hide();var c=new j.default("courseformat/actions:destroyModal");if(b){b.focus()}setTimeout(function(){a.destroy();c.resolve()},500)}},{key:"_getClosestActionMenuToogler",value:function _getClosestActionMenuToogler(a){var b=a.closest(this.selectors.ACTIONMENU);if(!b){return}return b.querySelector(this.selectors.ACTIONMENUTOGGLER)}}]);return b}(b.BaseComponent);a.default=C;return a.default}); //# sourceMappingURL=actions.min.js.map diff --git a/course/format/amd/build/local/content/actions.min.js.map b/course/format/amd/build/local/content/actions.min.js.map index e69cb48bcee..9a6f012f303 100644 --- a/course/format/amd/build/local/content/actions.min.js.map +++ b/course/format/amd/build/local/content/actions.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../../src/local/content/actions.js"],"names":["name","selectors","ACTIONLINK","SECTIONLINK","CMLINK","SECTIONNODE","TOGGLER","ADDSECTION","classes","DISABLED","state","addEventListener","element","_dispatchClick","_checkSectionlist","CourseEvents","sectionRefreshed","watch","handler","event","target","closest","classList","contains","preventDefault","methodName","_actionMethodName","dataset","action","requestName","charAt","toUpperCase","slice","_setAddSectionLocked","course","sectionlist","length","maxsections","sectionId","id","sectionInfo","reactive","get","exporter","getExporter","data","sectionid","sectiontitle","title","modalParams","body","Templates","render","_modalBodyRenderedPromise","modal","modalBody","getBody","currentElement","querySelector","_disableLink","generalSection","matches","for","getAttribute","dispatch","destroy","cmId","cmInfo","cmid","cmname","click","targetSectionId","targetCmId","dropData","cmDraggableData","nextcmid","section","cmlist","cmList","hassummary","rawtitle","saveButtonText","type","ModalFactory","types","SAVE_CANCEL","getRoot","on","ModalEvents","save","e","locked","targets","getElements","forEach","toggle","setElementLocked","style","pointerEvents","userSelect","add","setAttribute","Promise","resolve","reject","create","then","bodyRendered","setSaveButtonText","show","catch","BaseComponent"],"mappings":"oTA4BA,OACA,OACA,OAIA,O,8gFAGA,sBAAgB,MAAhB,CAAwB,CAAC,mBAAD,CAAsB,kBAAtB,CAA0C,SAA1C,CAAqD,QAArD,CAAxB,E,oIAOa,CAEL,KAAKA,IAAL,CAAY,iBAAZ,CAEA,KAAKC,SAAL,CAAiB,CACbC,UAAU,gBADG,CAEbC,WAAW,uBAFE,CAGbC,MAAM,kBAHO,CAIbC,WAAW,2BAJE,CAKbC,OAAO,2BALM,CAMbC,UAAU,6BANG,CAAjB,CASA,KAAKC,OAAL,CAAe,CACXC,QAAQ,WADG,CAGlB,C,8CAQUC,C,CAAO,YAEd,KAAKC,gBAAL,CACI,KAAKC,OADT,CAEI,OAFJ,CAGI,KAAKC,cAHT,EAMA,KAAKC,iBAAL,CAAuB,CAACJ,KAAK,CAALA,CAAD,CAAvB,EAEA,KAAKC,gBAAL,CACI,KAAKC,OADT,CAEIG,CAAY,CAACC,gBAFjB,CAGI,iBAAM,CAAA,CAAI,CAACF,iBAAL,CAAuB,CAACJ,KAAK,CAALA,CAAD,CAAvB,CAAN,CAHJ,CAKH,C,iDAOa,CACV,MAAO,CAEH,CAACO,KAAK,6BAAN,CAAsCC,OAAO,CAAE,KAAKJ,iBAApD,CAFG,CAIV,C,sDAEcK,C,CAAO,CAClB,GAAMC,CAAAA,CAAM,CAAGD,CAAK,CAACC,MAAN,CAAaC,OAAb,CAAqB,KAAKpB,SAAL,CAAeC,UAApC,CAAf,CACA,GAAI,CAACkB,CAAL,CAAa,CACT,MACH,CACD,GAAIA,CAAM,CAACE,SAAP,CAAiBC,QAAjB,CAA0B,KAAKf,OAAL,CAAaC,QAAvC,CAAJ,CAAsD,CAClDU,CAAK,CAACK,cAAN,GACA,MACH,CAGD,GAAMC,CAAAA,CAAU,CAAG,KAAKC,iBAAL,CAAuBN,CAAM,CAACO,OAAP,CAAeC,MAAtC,CAAnB,CAEA,GAAI,KAAKH,CAAL,UAAJ,CAAoC,CAChC,KAAKA,CAAL,EAAiBL,CAAjB,CAAyBD,CAAzB,CACH,CACJ,C,4DAEiBnB,C,CAAM,CACpB,GAAM6B,CAAAA,CAAW,CAAG7B,CAAI,CAAC8B,MAAL,CAAY,CAAZ,EAAeC,WAAf,GAA+B/B,CAAI,CAACgC,KAAL,CAAW,CAAX,CAAnD,CACA,wBAAkBH,CAAlB,CACH,C,8DAQ0B,IAARnB,CAAAA,CAAQ,GAARA,KAAQ,CAEvB,KAAKuB,oBAAL,CAA0BvB,CAAK,CAACwB,MAAN,CAAaC,WAAb,CAAyBC,MAAzB,CAAkC1B,CAAK,CAACwB,MAAN,CAAaG,WAAzE,CACH,C,yFAQyBjB,C,CAAQD,C,gHAExBmB,C,CAAYlB,CAAM,CAACO,OAAP,CAAeY,E,IAC5BD,C,kDAGCE,C,CAAc,KAAKC,QAAL,CAAcC,GAAd,CAAkB,SAAlB,CAA6BJ,CAA7B,C,CAEpBnB,CAAK,CAACK,cAAN,GAGMmB,C,CAAW,KAAKF,QAAL,CAAcG,WAAd,E,CACXC,C,CAAOF,CAAQ,CAACT,MAAT,CAAgB,KAAKO,QAAL,CAAc/B,KAA9B,C,CAGbmC,CAAI,CAACC,SAAL,CAAiBN,CAAW,CAACD,EAA7B,CACAM,CAAI,CAACE,YAAL,CAAoBP,CAAW,CAACQ,KAAhC,CAGMC,C,CAAc,CAChBD,KAAK,CAAE,iBAAU,mBAAV,CAA+B,MAA/B,CADS,CAEhBE,IAAI,CAAEC,UAAUC,MAAV,CAAiB,6CAAjB,CAAgEP,CAAhE,CAFU,C,iBAMA,MAAKQ,yBAAL,CAA+BJ,CAA/B,C,SAAdK,C,QAEAC,C,CAAY,cAAQD,CAAK,CAACE,OAAN,EAAR,EAAyB,CAAzB,C,CAGZC,C,CAAiBF,CAAS,CAACG,aAAV,WAA2B,KAAKzD,SAAL,CAAeE,WAA1C,sBAAkEmC,CAAlE,O,CACvB,KAAKqB,YAAL,CAAkBF,CAAlB,EACMG,C,CAAiBL,CAAS,CAACG,aAAV,WAA2B,KAAKzD,SAAL,CAAeE,WAA1C,sB,CACvB,KAAKwD,YAAL,CAAkBC,CAAlB,EAGAL,CAAS,CAAC5C,gBAAV,CAA2B,OAA3B,CAAoC,SAACQ,CAAD,CAAW,CAC3C,GAAMC,CAAAA,CAAM,CAAGD,CAAK,CAACC,MAArB,CACA,GAAI,CAACA,CAAM,CAACyC,OAAP,CAAe,GAAf,CAAD,EAA8C,SAAtB,EAAAzC,CAAM,CAACO,OAAP,CAAemC,GAAvC,EAA2D1C,CAAM,CAACO,OAAP,CAAeY,EAAf,SAA/D,CAAgG,CAC5F,MACH,CACD,GAAInB,CAAM,CAAC2C,YAAP,CAAoB,eAApB,CAAJ,CAA0C,CACtC,MACH,CACD5C,CAAK,CAACK,cAAN,GACA,CAAI,CAACiB,QAAL,CAAcuB,QAAd,CAAuB,aAAvB,CAAsC,CAAC1B,CAAD,CAAtC,CAAmDlB,CAAM,CAACO,OAAP,CAAeY,EAAlE,EACAe,CAAK,CAACW,OAAN,EACH,CAXD,E,6MAoBiB7C,C,CAAQD,C,kHAEnB+C,C,CAAO9C,CAAM,CAACO,OAAP,CAAeY,E,IACvB2B,C,kDAGCC,C,CAAS,KAAK1B,QAAL,CAAcC,GAAd,CAAkB,IAAlB,CAAwBwB,CAAxB,C,CAEf/C,CAAK,CAACK,cAAN,GAGMmB,C,CAAW,KAAKF,QAAL,CAAcG,WAAd,E,CACXC,C,CAAOF,CAAQ,CAACT,MAAT,CAAgB,KAAKO,QAAL,CAAc/B,KAA9B,C,CAGbmC,CAAI,CAACuB,IAAL,CAAYD,CAAM,CAAC5B,EAAnB,CACAM,CAAI,CAACwB,MAAL,CAAcF,CAAM,CAACnE,IAArB,CAGMiD,C,CAAc,CAChBD,KAAK,CAAE,iBAAU,kBAAV,CAA8B,MAA9B,CADS,CAEhBE,IAAI,CAAEC,UAAUC,MAAV,CAAiB,wCAAjB,CAA2DP,CAA3D,CAFU,C,iBAMA,MAAKQ,yBAAL,CAA+BJ,CAA/B,C,SAAdK,C,QAEAC,C,CAAY,cAAQD,CAAK,CAACE,OAAN,EAAR,EAAyB,CAAzB,C,CAGdC,C,CAAiBF,CAAS,CAACG,aAAV,WAA2B,KAAKzD,SAAL,CAAeG,MAA1C,sBAA6D8D,CAA7D,O,CACrB,KAAKP,YAAL,CAAkBF,CAAlB,EAGA,UAAAA,CAAc,CAACpC,OAAf,CAAuB,KAAKpB,SAAL,CAAeI,WAAtC,kCAAoDqD,aAApD,CAAkE,KAAKzD,SAAL,CAAeK,OAAjF,wBAA2FgE,KAA3F,GAGAf,CAAS,CAAC5C,gBAAV,CAA2B,OAA3B,CAAoC,SAACQ,CAAD,CAAW,CAC3C,GAAMC,CAAAA,CAAM,CAAGD,CAAK,CAACC,MAArB,CACA,GAAI,CAACA,CAAM,CAACyC,OAAP,CAAe,GAAf,CAAD,EAAwBzC,CAAM,CAACO,OAAP,CAAemC,GAAf,SAAxB,EAA4D1C,CAAM,CAACO,OAAP,CAAeY,EAAf,SAAhE,CAAiG,CAC7F,MACH,CACD,GAAInB,CAAM,CAAC2C,YAAP,CAAoB,eAApB,CAAJ,CAA0C,CACtC,MACH,CACD5C,CAAK,CAACK,cAAN,GAR2C,GAWvC+C,CAAAA,CAXuC,CAYvCC,CAZuC,CAa3C,GAA0B,IAAtB,EAAApD,CAAM,CAACO,OAAP,CAAemC,GAAnB,CAAgC,CAC5B,GAAMW,CAAAA,CAAQ,CAAG9B,CAAQ,CAAC+B,eAAT,CAAyB,CAAI,CAACjC,QAAL,CAAc/B,KAAvC,CAA8CU,CAAM,CAACO,OAAP,CAAeY,EAA7D,CAAjB,CACAgC,CAAe,CAAGE,CAAQ,CAAC3B,SAA3B,CACA0B,CAAU,CAAGC,CAAQ,CAACE,QACzB,CAJD,IAIO,CACH,GAAMC,CAAAA,CAAO,CAAG,CAAI,CAACnC,QAAL,CAAcC,GAAd,CAAkB,SAAlB,CAA6BtB,CAAM,CAACO,OAAP,CAAeY,EAA5C,CAAhB,CACAgC,CAAe,CAAGnD,CAAM,CAACO,OAAP,CAAeY,EAAjC,CACAiC,CAAU,QAAGI,CAAH,WAAGA,CAAH,QAAGA,CAAO,CAAEC,MAAT,CAAgB,CAAhB,CAChB,CAED,CAAI,CAACpC,QAAL,CAAcuB,QAAd,CAAuB,QAAvB,CAAiC,CAACE,CAAD,CAAjC,CAAyCK,CAAzC,CAA0DC,CAA1D,EACAlB,CAAK,CAACW,OAAN,EACH,CAzBD,E,4MAkCqB7C,C,CAAQD,C,yFAC7BA,CAAK,CAACK,cAAN,GACA,KAAKiB,QAAL,CAAcuB,QAAd,CAAuB,YAAvB,WAAqC5C,CAAM,CAACO,OAAP,CAAeY,EAApD,gBAA0D,CAA1D,E,kNASwBnB,C,CAAQD,C,0GAE1BmB,C,CAAYlB,CAAM,CAACO,OAAP,CAAeY,E,IAE5BD,C,kDAGCE,C,CAAc,KAAKC,QAAL,CAAcC,GAAd,CAAkB,SAAlB,CAA6BJ,CAA7B,C,CAEpBnB,CAAK,CAACK,cAAN,GAEMsD,C,WAAStC,CAAW,CAACqC,M,gBAAU,E,MACjCC,CAAM,CAAC1C,MAAP,EAAiBI,CAAW,CAACuC,UAA7B,EAA2CvC,CAAW,CAACwC,Q,mBAEjD/B,C,CAAc,CAChBD,KAAK,CAAE,iBAAU,SAAV,CAAqB,MAArB,CADS,CAEhBE,IAAI,CAAE,iBAAU,sBAAV,CAAkC,QAAlC,CAA4CV,CAAW,CAACQ,KAAxD,CAFU,CAGhBiC,cAAc,CAAE,iBAAU,QAAV,CAAoB,MAApB,CAHA,CAIhBC,IAAI,CAAEC,UAAaC,KAAb,CAAmBC,WAJT,C,iBAOA,MAAKhC,yBAAL,CAA+BJ,CAA/B,C,SAAdK,C,QAENA,CAAK,CAACgC,OAAN,GAAgBC,EAAhB,CACIC,UAAYC,IADhB,CAEI,SAAAC,CAAC,CAAI,CAEDA,CAAC,CAAClE,cAAF,GACA8B,CAAK,CAACW,OAAN,GACA,CAAI,CAACxB,QAAL,CAAcuB,QAAd,CAAuB,eAAvB,CAAwC,CAAC1B,CAAD,CAAxC,CACH,CAPL,E,kCAYA,KAAKG,QAAL,CAAcuB,QAAd,CAAuB,eAAvB,CAAwC,CAAC1B,CAAD,CAAxC,E,6LASaqD,C,CAAQ,YACnBC,CAAO,CAAG,KAAKC,WAAL,CAAiB,KAAK5F,SAAL,CAAeM,UAAhC,CADS,CAEzBqF,CAAO,CAACE,OAAR,CAAgB,SAAAlF,CAAO,CAAI,CACvBA,CAAO,CAACU,SAAR,CAAkByE,MAAlB,CAAyB,CAAI,CAACvF,OAAL,CAAaC,QAAtC,CAAgDkF,CAAhD,EACA,CAAI,CAACK,gBAAL,CAAsBpF,CAAtB,CAA+B+E,CAA/B,CACH,CAHD,CAIH,C,kDAOY/E,C,CAAS,CAClB,GAAIA,CAAJ,CAAa,CACTA,CAAO,CAACqF,KAAR,CAAcC,aAAd,CAA8B,MAA9B,CACAtF,CAAO,CAACqF,KAAR,CAAcE,UAAd,CAA2B,MAA3B,CACAvF,CAAO,CAACU,SAAR,CAAkB8E,GAAlB,CAAsB,KAAK5F,OAAL,CAAaC,QAAnC,EACAG,CAAO,CAACyF,YAAR,CAAqB,eAArB,KACAzF,CAAO,CAACD,gBAAR,CAAyB,OAAzB,CAAkC,SAAAQ,CAAK,QAAIA,CAAAA,CAAK,CAACK,cAAN,EAAJ,CAAvC,CACH,CACJ,C,4EAQyByB,C,CAAa,CACnC,MAAO,IAAIqD,CAAAA,OAAJ,CAAY,SAACC,CAAD,CAAUC,CAAV,CAAqB,CACpCrB,UAAasB,MAAb,CAAoBxD,CAApB,EAAiCyD,IAAjC,CAAsC,SAACpD,CAAD,CAAW,CAE7CA,CAAK,CAACgC,OAAN,GAAgBC,EAAhB,CAAmBC,UAAYmB,YAA/B,CAA6C,UAAM,CAC/CJ,CAAO,CAACjD,CAAD,CACV,CAFD,EAIA,GAAIL,CAAW,CAACgC,cAAZ,SAAJ,CAA8C,CAC1C3B,CAAK,CAACsD,iBAAN,CAAwB3D,CAAW,CAACgC,cAApC,CACH,CACD3B,CAAK,CAACuD,IAAN,EAEH,CAXD,EAWGC,KAXH,CAWS,UAAM,CACXN,CAAM,6BACT,CAbD,CAcH,CAfM,CAgBV,C,cAtUwBO,e","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course state actions dispatcher.\n *\n * This module captures all data-dispatch links in the course content and dispatch the proper\n * state mutation, including any confirmation and modal required.\n *\n * @module core_courseformat/local/content/actions\n * @class core_courseformat/local/content/actions\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport ModalFactory from 'core/modal_factory';\nimport ModalEvents from 'core/modal_events';\nimport Templates from 'core/templates';\nimport {prefetchStrings} from 'core/prefetch';\nimport {get_string as getString} from 'core/str';\nimport {getList} from 'core/normalise';\nimport * as CourseEvents from 'core_course/events';\n\n// Load global strings.\nprefetchStrings('core', ['movecoursesection', 'movecoursemodule', 'confirm', 'delete']);\n\nexport default class extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'content_actions';\n // Default query selectors.\n this.selectors = {\n ACTIONLINK: `[data-action]`,\n SECTIONLINK: `[data-for='section']`,\n CMLINK: `[data-for='cm']`,\n SECTIONNODE: `[data-for='sectionnode']`,\n TOGGLER: `[data-toggle='collapse']`,\n ADDSECTION: `[data-action='addSection']`,\n };\n // Component css classes.\n this.classes = {\n DISABLED: `disabled`,\n };\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the state data.\n *\n */\n stateReady(state) {\n // Delegate dispatch clicks.\n this.addEventListener(\n this.element,\n 'click',\n this._dispatchClick\n );\n // Check section limit.\n this._checkSectionlist({state});\n // Add an Event listener to recalculate limits it if a section HTML is altered.\n this.addEventListener(\n this.element,\n CourseEvents.sectionRefreshed,\n () => this._checkSectionlist({state})\n );\n }\n\n /**\n * Return the component watchers.\n *\n * @returns {Array} of watchers\n */\n getWatchers() {\n return [\n // Check section limit.\n {watch: `course.sectionlist:updated`, handler: this._checkSectionlist},\n ];\n }\n\n _dispatchClick(event) {\n const target = event.target.closest(this.selectors.ACTIONLINK);\n if (!target) {\n return;\n }\n if (target.classList.contains(this.classes.DISABLED)) {\n event.preventDefault();\n return;\n }\n\n // Invoke proper method.\n const methodName = this._actionMethodName(target.dataset.action);\n\n if (this[methodName] !== undefined) {\n this[methodName](target, event);\n }\n }\n\n _actionMethodName(name) {\n const requestName = name.charAt(0).toUpperCase() + name.slice(1);\n return `_request${requestName}`;\n }\n\n /**\n * Check the section list and disable some options if needed.\n *\n * @param {Object} detail the update details.\n * @param {Object} detail.state the state object.\n */\n _checkSectionlist({state}) {\n // Disable \"add section\" actions if the course max sections has been exceeded.\n this._setAddSectionLocked(state.course.sectionlist.length > state.course.maxsections);\n }\n\n /**\n * Handle a move section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestMoveSection(target, event) {\n // Check we have an id.\n const sectionId = target.dataset.id;\n if (!sectionId) {\n return;\n }\n const sectionInfo = this.reactive.get('section', sectionId);\n\n event.preventDefault();\n\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(this.reactive.state);\n\n // Add the target section id and title.\n data.sectionid = sectionInfo.id;\n data.sectiontitle = sectionInfo.title;\n\n // Build the modal parameters from the event data.\n const modalParams = {\n title: getString('movecoursesection', 'core'),\n body: Templates.render('core_courseformat/local/content/movesection', data),\n };\n\n // Create the modal.\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n const modalBody = getList(modal.getBody())[0];\n\n // Disable current element and section zero.\n const currentElement = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-id='${sectionId}']`);\n this._disableLink(currentElement);\n const generalSection = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-number='0']`);\n this._disableLink(generalSection);\n\n // Capture click.\n modalBody.addEventListener('click', (event) => {\n const target = event.target;\n if (!target.matches('a') || target.dataset.for != 'section' || target.dataset.id === undefined) {\n return;\n }\n if (target.getAttribute('aria-disabled')) {\n return;\n }\n event.preventDefault();\n this.reactive.dispatch('sectionMove', [sectionId], target.dataset.id);\n modal.destroy();\n });\n }\n\n /**\n * Handle a move cm request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestMoveCm(target, event) {\n // Check we have an id.\n const cmId = target.dataset.id;\n if (!cmId) {\n return;\n }\n const cmInfo = this.reactive.get('cm', cmId);\n\n event.preventDefault();\n\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(this.reactive.state);\n\n // Add the target cm info.\n data.cmid = cmInfo.id;\n data.cmname = cmInfo.name;\n\n // Build the modal parameters from the event data.\n const modalParams = {\n title: getString('movecoursemodule', 'core'),\n body: Templates.render('core_courseformat/local/content/movecm', data),\n };\n\n // Create the modal.\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n const modalBody = getList(modal.getBody())[0];\n\n // Disable current element.\n let currentElement = modalBody.querySelector(`${this.selectors.CMLINK}[data-id='${cmId}']`);\n this._disableLink(currentElement);\n\n // Open the cm section node if possible.\n currentElement.closest(this.selectors.SECTIONNODE)?.querySelector(this.selectors.TOGGLER)?.click();\n\n // Capture click.\n modalBody.addEventListener('click', (event) => {\n const target = event.target;\n if (!target.matches('a') || target.dataset.for === undefined || target.dataset.id === undefined) {\n return;\n }\n if (target.getAttribute('aria-disabled')) {\n return;\n }\n event.preventDefault();\n\n // Get draggable data from cm or section to dispatch.\n let targetSectionId;\n let targetCmId;\n if (target.dataset.for == 'cm') {\n const dropData = exporter.cmDraggableData(this.reactive.state, target.dataset.id);\n targetSectionId = dropData.sectionid;\n targetCmId = dropData.nextcmid;\n } else {\n const section = this.reactive.get('section', target.dataset.id);\n targetSectionId = target.dataset.id;\n targetCmId = section?.cmlist[0];\n }\n\n this.reactive.dispatch('cmMove', [cmId], targetSectionId, targetCmId);\n modal.destroy();\n });\n }\n\n /**\n * Handle a create section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestAddSection(target, event) {\n event.preventDefault();\n this.reactive.dispatch('addSection', target.dataset.id ?? 0);\n }\n\n /**\n * Handle a delete section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestDeleteSection(target, event) {\n // Check we have an id.\n const sectionId = target.dataset.id;\n\n if (!sectionId) {\n return;\n }\n const sectionInfo = this.reactive.get('section', sectionId);\n\n event.preventDefault();\n\n const cmList = sectionInfo.cmlist ?? [];\n if (cmList.length || sectionInfo.hassummary || sectionInfo.rawtitle) {\n // We need confirmation if the section has something.\n const modalParams = {\n title: getString('confirm', 'core'),\n body: getString('confirmdeletesection', 'moodle', sectionInfo.title),\n saveButtonText: getString('delete', 'core'),\n type: ModalFactory.types.SAVE_CANCEL,\n };\n\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n modal.getRoot().on(\n ModalEvents.save,\n e => {\n // Stop the default save button behaviour which is to close the modal.\n e.preventDefault();\n modal.destroy();\n this.reactive.dispatch('sectionDelete', [sectionId]);\n }\n );\n return;\n } else {\n // We don't need confirmation to delete empty sections.\n this.reactive.dispatch('sectionDelete', [sectionId]);\n }\n }\n\n /**\n * Disable all add sections actions.\n *\n * @param {boolean} locked the new locked value.\n */\n _setAddSectionLocked(locked) {\n const targets = this.getElements(this.selectors.ADDSECTION);\n targets.forEach(element => {\n element.classList.toggle(this.classes.DISABLED, locked);\n this.setElementLocked(element, locked);\n });\n }\n\n /**\n * Replace an element with a copy with a different tag name.\n *\n * @param {Element} element the original element\n */\n _disableLink(element) {\n if (element) {\n element.style.pointerEvents = 'none';\n element.style.userSelect = 'none';\n element.classList.add(this.classes.DISABLED);\n element.setAttribute('aria-disabled', true);\n element.addEventListener('click', event => event.preventDefault());\n }\n }\n\n /**\n * Render a modal and return a body ready promise.\n *\n * @param {object} modalParams the modal params\n * @return {Promise} the modal body ready promise\n */\n _modalBodyRenderedPromise(modalParams) {\n return new Promise((resolve, reject) => {\n ModalFactory.create(modalParams).then((modal) => {\n // Handle body loading event.\n modal.getRoot().on(ModalEvents.bodyRendered, () => {\n resolve(modal);\n });\n // Configure some extra modal params.\n if (modalParams.saveButtonText !== undefined) {\n modal.setSaveButtonText(modalParams.saveButtonText);\n }\n modal.show();\n return;\n }).catch(() => {\n reject(`Cannot load modal content`);\n });\n });\n }\n}\n"],"file":"actions.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/content/actions.js"],"names":["name","selectors","ACTIONLINK","SECTIONLINK","CMLINK","SECTIONNODE","MODALTOGGLER","ADDSECTION","CONTENTTREE","ACTIONMENU","ACTIONMENUTOGGLER","classes","DISABLED","state","addEventListener","element","_dispatchClick","_checkSectionlist","CourseEvents","sectionRefreshed","watch","handler","event","target","closest","classList","contains","preventDefault","methodName","_actionMethodName","dataset","action","requestName","charAt","toUpperCase","slice","_setAddSectionLocked","course","sectionlist","length","maxsections","sectionId","id","sectionInfo","reactive","get","editTools","_getClosestActionMenuToogler","exporter","getExporter","data","sectionid","sectiontitle","title","modalParams","body","Templates","render","_modalBodyRenderedPromise","modal","modalBody","getBody","currentElement","querySelector","_disableLink","generalSection","ContentTree","SECTION","TOGGLER","COLLAPSE","matches","for","getAttribute","dispatch","_destroyModal","cmId","cmInfo","cmid","cmname","ENTER","sectionnode","toggler","find","collapsibleId","attr","replace","collapse","targetSectionId","targetCmId","dropData","cmDraggableData","nextcmid","section","cmlist","cmList","hassummary","rawtitle","saveButtonText","type","ModalFactory","types","SAVE_CANCEL","getRoot","on","ModalEvents","save","e","destroy","locked","targets","getElements","forEach","toggle","setElementLocked","style","pointerEvents","userSelect","add","setAttribute","Promise","resolve","reject","create","then","setRemoveOnClose","bodyRendered","setSaveButtonText","show","catch","hide","pendingDestroy","Pending","focus","setTimeout","actionMenu","BaseComponent"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course state actions dispatcher.\n *\n * This module captures all data-dispatch links in the course content and dispatch the proper\n * state mutation, including any confirmation and modal required.\n *\n * @module core_courseformat/local/content/actions\n * @class core_courseformat/local/content/actions\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport ModalFactory from 'core/modal_factory';\nimport ModalEvents from 'core/modal_events';\nimport Templates from 'core/templates';\nimport {prefetchStrings} from 'core/prefetch';\nimport {get_string as getString} from 'core/str';\nimport {getList} from 'core/normalise';\nimport * as CourseEvents from 'core_course/events';\nimport Pending from 'core/pending';\nimport ContentTree from 'core_courseformat/local/courseeditor/contenttree';\n// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-79179 is integrated.\nimport jQuery from 'jquery';\n\n// Load global strings.\nprefetchStrings('core', ['movecoursesection', 'movecoursemodule', 'confirm', 'delete']);\n\nexport default class extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'content_actions';\n // Default query selectors.\n this.selectors = {\n ACTIONLINK: `[data-action]`,\n // Move modal selectors.\n SECTIONLINK: `[data-for='section']`,\n CMLINK: `[data-for='cm']`,\n SECTIONNODE: `[data-for='sectionnode']`,\n MODALTOGGLER: `[data-toggle='collapse']`,\n ADDSECTION: `[data-action='addSection']`,\n CONTENTTREE: `#destination-selector`,\n ACTIONMENU: `.action-menu`,\n ACTIONMENUTOGGLER: `[data-toggle=\"dropdown\"]`,\n };\n // Component css classes.\n this.classes = {\n DISABLED: `disabled`,\n };\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the state data.\n *\n */\n stateReady(state) {\n // Delegate dispatch clicks.\n this.addEventListener(\n this.element,\n 'click',\n this._dispatchClick\n );\n // Check section limit.\n this._checkSectionlist({state});\n // Add an Event listener to recalculate limits it if a section HTML is altered.\n this.addEventListener(\n this.element,\n CourseEvents.sectionRefreshed,\n () => this._checkSectionlist({state})\n );\n }\n\n /**\n * Return the component watchers.\n *\n * @returns {Array} of watchers\n */\n getWatchers() {\n return [\n // Check section limit.\n {watch: `course.sectionlist:updated`, handler: this._checkSectionlist},\n ];\n }\n\n _dispatchClick(event) {\n const target = event.target.closest(this.selectors.ACTIONLINK);\n if (!target) {\n return;\n }\n if (target.classList.contains(this.classes.DISABLED)) {\n event.preventDefault();\n return;\n }\n\n // Invoke proper method.\n const methodName = this._actionMethodName(target.dataset.action);\n\n if (this[methodName] !== undefined) {\n this[methodName](target, event);\n }\n }\n\n _actionMethodName(name) {\n const requestName = name.charAt(0).toUpperCase() + name.slice(1);\n return `_request${requestName}`;\n }\n\n /**\n * Check the section list and disable some options if needed.\n *\n * @param {Object} detail the update details.\n * @param {Object} detail.state the state object.\n */\n _checkSectionlist({state}) {\n // Disable \"add section\" actions if the course max sections has been exceeded.\n this._setAddSectionLocked(state.course.sectionlist.length > state.course.maxsections);\n }\n\n /**\n * Handle a move section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestMoveSection(target, event) {\n // Check we have an id.\n const sectionId = target.dataset.id;\n if (!sectionId) {\n return;\n }\n const sectionInfo = this.reactive.get('section', sectionId);\n\n event.preventDefault();\n\n // The section edit menu to refocus on end.\n const editTools = this._getClosestActionMenuToogler(target);\n\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(this.reactive.state);\n\n // Add the target section id and title.\n data.sectionid = sectionInfo.id;\n data.sectiontitle = sectionInfo.title;\n\n // Build the modal parameters from the event data.\n const modalParams = {\n title: getString('movecoursesection', 'core'),\n body: Templates.render('core_courseformat/local/content/movesection', data),\n };\n\n // Create the modal.\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n const modalBody = getList(modal.getBody())[0];\n\n // Disable current element and section zero.\n const currentElement = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-id='${sectionId}']`);\n this._disableLink(currentElement);\n const generalSection = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-number='0']`);\n this._disableLink(generalSection);\n\n // Setup keyboard navigation.\n new ContentTree(\n modalBody.querySelector(this.selectors.CONTENTTREE),\n {\n SECTION: this.selectors.SECTIONNODE,\n TOGGLER: this.selectors.MODALTOGGLER,\n COLLAPSE: this.selectors.MODALTOGGLER,\n },\n true\n );\n\n // Capture click.\n modalBody.addEventListener('click', (event) => {\n const target = event.target;\n if (!target.matches('a') || target.dataset.for != 'section' || target.dataset.id === undefined) {\n return;\n }\n if (target.getAttribute('aria-disabled')) {\n return;\n }\n event.preventDefault();\n this.reactive.dispatch('sectionMove', [sectionId], target.dataset.id);\n this._destroyModal(modal, editTools);\n });\n }\n\n /**\n * Handle a move cm request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestMoveCm(target, event) {\n // Check we have an id.\n const cmId = target.dataset.id;\n if (!cmId) {\n return;\n }\n const cmInfo = this.reactive.get('cm', cmId);\n\n event.preventDefault();\n\n // The section edit menu to refocus on end.\n const editTools = this._getClosestActionMenuToogler(target);\n\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(this.reactive.state);\n\n // Add the target cm info.\n data.cmid = cmInfo.id;\n data.cmname = cmInfo.name;\n\n // Build the modal parameters from the event data.\n const modalParams = {\n title: getString('movecoursemodule', 'core'),\n body: Templates.render('core_courseformat/local/content/movecm', data),\n };\n\n // Create the modal.\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n const modalBody = getList(modal.getBody())[0];\n\n // Disable current element.\n let currentElement = modalBody.querySelector(`${this.selectors.CMLINK}[data-id='${cmId}']`);\n this._disableLink(currentElement);\n\n // Setup keyboard navigation.\n new ContentTree(\n modalBody.querySelector(this.selectors.CONTENTTREE),\n {\n SECTION: this.selectors.SECTIONNODE,\n TOGGLER: this.selectors.MODALTOGGLER,\n COLLAPSE: this.selectors.MODALTOGGLER,\n ENTER: this.selectors.SECTIONLINK,\n }\n );\n\n // Open the cm section node if possible (Bootstrap 4 uses jQuery to interact with collapsibles).\n // All jQuery int this code can be replaced when MDL-79179 is integrated.\n const sectionnode = currentElement.closest(this.selectors.SECTIONNODE);\n const toggler = jQuery(sectionnode).find(this.selectors.MODALTOGGLER);\n let collapsibleId = toggler.data('target') ?? toggler.attr('href');\n if (collapsibleId) {\n // We cannot be sure we have # in the id element name.\n collapsibleId = collapsibleId.replace('#', '');\n jQuery(`#${collapsibleId}`).collapse('toggle');\n }\n\n // Capture click.\n modalBody.addEventListener('click', (event) => {\n const target = event.target;\n if (!target.matches('a') || target.dataset.for === undefined || target.dataset.id === undefined) {\n return;\n }\n if (target.getAttribute('aria-disabled')) {\n return;\n }\n event.preventDefault();\n\n // Get draggable data from cm or section to dispatch.\n let targetSectionId;\n let targetCmId;\n if (target.dataset.for == 'cm') {\n const dropData = exporter.cmDraggableData(this.reactive.state, target.dataset.id);\n targetSectionId = dropData.sectionid;\n targetCmId = dropData.nextcmid;\n } else {\n const section = this.reactive.get('section', target.dataset.id);\n targetSectionId = target.dataset.id;\n targetCmId = section?.cmlist[0];\n }\n\n this.reactive.dispatch('cmMove', [cmId], targetSectionId, targetCmId);\n this._destroyModal(modal, editTools);\n });\n }\n\n /**\n * Handle a create section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestAddSection(target, event) {\n event.preventDefault();\n this.reactive.dispatch('addSection', target.dataset.id ?? 0);\n }\n\n /**\n * Handle a delete section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestDeleteSection(target, event) {\n // Check we have an id.\n const sectionId = target.dataset.id;\n\n if (!sectionId) {\n return;\n }\n const sectionInfo = this.reactive.get('section', sectionId);\n\n event.preventDefault();\n\n const cmList = sectionInfo.cmlist ?? [];\n if (cmList.length || sectionInfo.hassummary || sectionInfo.rawtitle) {\n // We need confirmation if the section has something.\n const modalParams = {\n title: getString('confirm', 'core'),\n body: getString('confirmdeletesection', 'moodle', sectionInfo.title),\n saveButtonText: getString('delete', 'core'),\n type: ModalFactory.types.SAVE_CANCEL,\n };\n\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n modal.getRoot().on(\n ModalEvents.save,\n e => {\n // Stop the default save button behaviour which is to close the modal.\n e.preventDefault();\n modal.destroy();\n this.reactive.dispatch('sectionDelete', [sectionId]);\n }\n );\n return;\n } else {\n // We don't need confirmation to delete empty sections.\n this.reactive.dispatch('sectionDelete', [sectionId]);\n }\n }\n\n /**\n * Disable all add sections actions.\n *\n * @param {boolean} locked the new locked value.\n */\n _setAddSectionLocked(locked) {\n const targets = this.getElements(this.selectors.ADDSECTION);\n targets.forEach(element => {\n element.classList.toggle(this.classes.DISABLED, locked);\n this.setElementLocked(element, locked);\n });\n }\n\n /**\n * Replace an element with a copy with a different tag name.\n *\n * @param {Element} element the original element\n */\n _disableLink(element) {\n if (element) {\n element.style.pointerEvents = 'none';\n element.style.userSelect = 'none';\n element.classList.add(this.classes.DISABLED);\n element.setAttribute('aria-disabled', true);\n element.addEventListener('click', event => event.preventDefault());\n }\n }\n\n /**\n * Render a modal and return a body ready promise.\n *\n * @param {object} modalParams the modal params\n * @return {Promise} the modal body ready promise\n */\n _modalBodyRenderedPromise(modalParams) {\n return new Promise((resolve, reject) => {\n ModalFactory.create(modalParams).then((modal) => {\n modal.setRemoveOnClose(true);\n // Handle body loading event.\n modal.getRoot().on(ModalEvents.bodyRendered, () => {\n resolve(modal);\n });\n // Configure some extra modal params.\n if (modalParams.saveButtonText !== undefined) {\n modal.setSaveButtonText(modalParams.saveButtonText);\n }\n modal.show();\n return;\n }).catch(() => {\n reject(`Cannot load modal content`);\n });\n });\n }\n\n /**\n * Hide and later destroy a modal.\n *\n * Behat will fail if we remove the modal while some boostrap collapse is executing.\n *\n * @param {Modal} modal\n * @param {HTMLElement} element the dom element to focus on.\n */\n _destroyModal(modal, element) {\n modal.hide();\n const pendingDestroy = new Pending(`courseformat/actions:destroyModal`);\n if (element) {\n element.focus();\n }\n setTimeout(() =>{\n modal.destroy();\n pendingDestroy.resolve();\n }, 500);\n }\n\n /**\n * Get the closest actions menu toggler to an action element.\n *\n * @param {HTMLElement} element the action link element\n * @returns {HTMLElement|undefined}\n */\n _getClosestActionMenuToogler(element) {\n const actionMenu = element.closest(this.selectors.ACTIONMENU);\n if (!actionMenu) {\n return undefined;\n }\n return actionMenu.querySelector(this.selectors.ACTIONMENUTOGGLER);\n }\n}\n"],"file":"actions.min.js"} \ No newline at end of file diff --git a/course/format/amd/build/local/courseeditor/contenttree.min.js b/course/format/amd/build/local/courseeditor/contenttree.min.js new file mode 100644 index 00000000000..1fdf2660d24 --- /dev/null +++ b/course/format/amd/build/local/courseeditor/contenttree.min.js @@ -0,0 +1,2 @@ +define ("core_courseformat/local/courseeditor/contenttree",["exports","jquery","core/tree","core/normalise"],function(a,b,c,d){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=e(b);c=e(c);function e(a){return a&&a.__esModule?a:{default:a}}function f(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){f=function(a){return typeof a}}else{f=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return f(a)}function g(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function h(a,b){for(var c=0,d;c.\n\n/**\n * Course index keyboard navigation and aria-tree compatibility.\n *\n * Node tree and bootstrap collapsibles don't use the same HTML structure. However,\n * all keybindings and logic is compatible. This class translate the primitive opetations\n * to a bootstrap collapsible structure.\n *\n * @module core_courseformat/local/courseindex/keyboardnav\n * @class core_courseformat/local/courseindex/keyboardnav\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n// The core/tree uses jQuery to expand all nodes.\nimport jQuery from 'jquery';\nimport Tree from 'core/tree';\nimport {getList} from 'core/normalise';\n\nexport default class extends Tree {\n\n /**\n * Setup the core/tree keyboard navigation.\n *\n * @param {Element|undefined} mainElement an alternative main element in case it is not from the parent component\n * @param {Object|undefined} selectors alternative selectors\n * @param {boolean} preventcache if the elements cache must be disabled.\n */\n constructor(mainElement, selectors, preventcache) {\n // Init this value with the parent DOM element.\n super(mainElement);\n\n // Get selectors from parent.\n this.selectors = {\n SECTION: selectors.SECTION,\n TOGGLER: selectors.TOGGLER,\n COLLAPSE: selectors.COLLAPSE,\n ENTER: selectors.ENTER ?? selectors.TOGGLER,\n };\n\n // The core/tree library saves the visible elements cache inside the main tree node.\n // However, in edit mode content can change suddenly so we need to refresh caches when needed.\n if (preventcache) {\n this._getVisibleItems = this.getVisibleItems;\n this.getVisibleItems = () => {\n this.refreshVisibleItemsCache();\n return this._getVisibleItems();\n };\n }\n // All jQuery events can be replaced when MDL-79179 is integrated.\n this.treeRoot.on('hidden.bs.collapse shown.bs.collapse', () => {\n this.refreshVisibleItemsCache();\n });\n // Register a custom callback for pressing enter key.\n this.registerEnterCallback(this.enterCallback.bind(this));\n }\n\n /**\n * Return the current active node.\n *\n * @return {Element|undefined} the active item if any\n */\n getActiveItem() {\n const activeItem = this.treeRoot.data('activeItem');\n if (activeItem) {\n return getList(activeItem)[0];\n }\n return undefined;\n }\n\n /**\n * Handle enter key on a collpasible node.\n *\n * @param {JQuery} jQueryItem the jQuery object\n */\n enterCallback(jQueryItem) {\n const item = getList(jQueryItem)[0];\n if (this.isGroupItem(jQueryItem)) {\n // Group elements is like clicking a topic but without loosing the focus.\n const enter = item.querySelector(this.selectors.ENTER);\n if (enter.getAttribute('href') !== '#') {\n window.location.href = enter.getAttribute('href');\n }\n enter.click();\n } else {\n // Activity links just follow the link href.\n const link = item.querySelector('a');\n if (link.getAttribute('href') !== '#') {\n window.location.href = link.getAttribute('href');\n } else {\n link.click();\n }\n return;\n }\n }\n\n /**\n * Check if a gorup item is collapsed.\n *\n * @param {JQuery} jQueryItem the jQuery object\n * @returns {boolean} if the element is collapsed\n */\n isGroupCollapsed(jQueryItem) {\n const item = getList(jQueryItem)[0];\n const toggler = item.querySelector(`[aria-expanded]`);\n return toggler.getAttribute('aria-expanded') === 'false';\n }\n\n /**\n * Toggle a group item.\n *\n * @param {JQuery} item the jQuery object\n */\n toggleGroup(item) {\n // All jQuery in this segment of code can be replaced when MDL-79179 is integrated.\n const toggler = item.find(this.selectors.COLLAPSE);\n let collapsibleId = toggler.data('target') ?? toggler.attr('href');\n if (!collapsibleId) {\n return;\n }\n collapsibleId = collapsibleId.replace('#', '');\n\n // Bootstrap 4 uses jQuery to interact with collapsibles.\n const collapsible = jQuery(`#${collapsibleId}`);\n if (collapsible.length) {\n jQuery(`#${collapsibleId}`).collapse('toggle');\n }\n }\n\n /**\n * Expand a group item.\n *\n * @param {JQuery} item the jQuery object\n */\n expandGroup(item) {\n if (this.isGroupCollapsed(item)) {\n this.toggleGroup(item);\n }\n }\n\n /**\n * Collpase a group item.\n *\n * @param {JQuery} item the jQuery object\n */\n collapseGroup(item) {\n if (!this.isGroupCollapsed(item)) {\n this.toggleGroup(item);\n }\n }\n\n /**\n * Expand all groups.\n */\n expandAllGroups() {\n const togglers = getList(this.treeRoot)[0].querySelectorAll(this.selectors.SECTION);\n togglers.forEach(item => {\n this.expandGroup(jQuery(item));\n });\n }\n}\n"],"file":"contenttree.min.js"} \ No newline at end of file diff --git a/course/format/amd/build/local/courseindex/courseindex.min.js b/course/format/amd/build/local/courseindex/courseindex.min.js index 62ed1c88960..e5188f5145a 100644 --- a/course/format/amd/build/local/courseindex/courseindex.min.js +++ b/course/format/amd/build/local/courseindex/courseindex.min.js @@ -1,2 +1,2 @@ -define ("core_courseformat/local/courseindex/courseindex",["exports","core/reactive","core_courseformat/courseeditor","jquery","core_courseformat/local/courseindex/keyboardnav"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;d=f(d);e=f(e);function f(a){return a&&a.__esModule?a:{default:a}}function g(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){g=function(a){return typeof a}}else{g=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return g(a)}function h(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function i(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var i=a.apply(b,c);function f(a){h(i,d,e,f,g,"next",a)}function g(a){h(i,d,e,f,g,"throw",a)}f(void 0)})}}function j(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function k(a,b){for(var c=0,d;cb.length){a.removeChild(a.lastChild)}}},{key:"_deleteCm",value:function _deleteCm(a){var b=a.element;delete this.cms[b.id]}},{key:"_deleteSection",value:function _deleteSection(a){var b=a.element;delete this.sections[b.id]}}],[{key:"init",value:function init(a,d){return new b({element:document.getElementById(a),reactive:(0,c.getCurrentCourseEditor)(),selectors:d})}}]);return b}(b.BaseComponent);a.default=t;return a.default}); +define ("core_courseformat/local/courseindex/courseindex",["exports","core/reactive","core_courseformat/courseeditor","jquery","core_courseformat/local/courseeditor/contenttree"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;d=f(d);e=f(e);function f(a){return a&&a.__esModule?a:{default:a}}function g(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){g=function(a){return typeof a}}else{g=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return g(a)}function h(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function i(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var i=a.apply(b,c);function f(a){h(i,d,e,f,g,"next",a)}function g(a){h(i,d,e,f,g,"throw",a)}f(void 0)})}}function j(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function k(a,b){for(var c=0,d;cb.length){a.removeChild(a.lastChild)}}},{key:"_deleteCm",value:function _deleteCm(a){var b=a.element;delete this.cms[b.id]}},{key:"_deleteSection",value:function _deleteSection(a){var b=a.element;delete this.sections[b.id]}}],[{key:"init",value:function init(a,d){return new b({element:document.getElementById(a),reactive:(0,c.getCurrentCourseEditor)(),selectors:d})}}]);return b}(b.BaseComponent);a.default=t;return a.default}); //# sourceMappingURL=courseindex.min.js.map diff --git a/course/format/amd/build/local/courseindex/courseindex.min.js.map b/course/format/amd/build/local/courseindex/courseindex.min.js.map index 79c16e934cf..87e6ad17a68 100644 --- a/course/format/amd/build/local/courseindex/courseindex.min.js.map +++ b/course/format/amd/build/local/courseindex/courseindex.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../../src/local/courseindex/courseindex.js"],"names":["Component","name","selectors","SECTION","SECTION_CMLIST","CM","TOGGLER","COLLAPSE","DRAWER","classes","SECTIONHIDDEN","CMHIDDEN","SECTIONCURRENT","COLLAPSED","SHOW","sections","cms","addEventListener","element","_sectionTogglers","getElements","forEach","section","dataset","id","cm","treeNav","TreeNav","watch","handler","_refreshSectionCollapsed","_createCm","_deleteCm","_createSection","_deleteSection","_refreshCourseSectionlist","_refreshSectionCmlist","event","sectionlink","target","closest","isChevron","toggler","querySelector","isCollapsed","classList","contains","sectionId","getAttribute","reactive","dispatch","isactive","getElement","Error","_expandSectionNode","forceValue","collapsibleId","replace","collapsible","document","getElementById","togglerValue","collapse","state","fakeelement","createElement","add","innerHTML","get","sectionid","exporter","getExporter","data","renderComponent","newcomponent","newelement","parentNode","replaceChild","course","cmlist","listparent","_fixOrder","sectionlist","container","neworder","allitems","length","remove","itemid","index","item","currentitem","children","append","insertBefore","removeChild","lastChild","BaseComponent"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course index main component.\n *\n * @module core_courseformat/local/courseindex/courseindex\n * @class core_courseformat/local/courseindex/courseindex\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport jQuery from 'jquery';\nimport TreeNav from 'core_courseformat/local/courseindex/keyboardnav';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'courseindex';\n // Default query selectors.\n this.selectors = {\n SECTION: `[data-for='section']`,\n SECTION_CMLIST: `[data-for='cmlist']`,\n CM: `[data-for='cm']`,\n TOGGLER: `[data-action=\"togglecourseindexsection\"]`,\n COLLAPSE: `[data-toggle=\"collapse\"]`,\n DRAWER: `.drawer`,\n };\n // Default classes to toggle on refresh.\n this.classes = {\n SECTIONHIDDEN: 'dimmed',\n CMHIDDEN: 'dimmed',\n SECTIONCURRENT: 'current',\n COLLAPSED: `collapsed`,\n SHOW: `show`,\n };\n // Arrays to keep cms and sections elements.\n this.sections = {};\n this.cms = {};\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new Component({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n */\n stateReady() {\n // Activate section togglers.\n this.addEventListener(this.element, 'click', this._sectionTogglers);\n\n // Get cms and sections elements.\n const sections = this.getElements(this.selectors.SECTION);\n sections.forEach((section) => {\n this.sections[section.dataset.id] = section;\n });\n const cms = this.getElements(this.selectors.CM);\n cms.forEach((cm) => {\n this.cms[cm.dataset.id] = cm;\n });\n\n // Configure Aria Tree.\n this.treeNav = new TreeNav(this);\n }\n\n getWatchers() {\n return [\n {watch: `section.isactive:updated`, handler: this._refreshSectionCollapsed},\n {watch: `cm:created`, handler: this._createCm},\n {watch: `cm:deleted`, handler: this._deleteCm},\n {watch: `section:created`, handler: this._createSection},\n {watch: `section:deleted`, handler: this._deleteSection},\n // Sections and cm sorting.\n {watch: `course.sectionlist:updated`, handler: this._refreshCourseSectionlist},\n {watch: `section.cmlist:updated`, handler: this._refreshSectionCmlist},\n ];\n }\n\n /**\n * Setup sections toggler.\n *\n * Toggler click is delegated to the main course index element because new sections can\n * appear at any moment and this way we prevent accidental double bindings.\n *\n * @param {Event} event the triggered event\n */\n _sectionTogglers(event) {\n const sectionlink = event.target.closest(this.selectors.TOGGLER);\n const isChevron = event.target.closest(this.selectors.COLLAPSE);\n\n if (sectionlink || isChevron) {\n\n const section = event.target.closest(this.selectors.SECTION);\n const toggler = section.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (isChevron || isCollapsed) {\n // Update the state.\n const sectionId = section.getAttribute('data-id');\n this.reactive.dispatch(\n 'sectionPreferences',\n [sectionId],\n {\n isactive: isCollapsed,\n },\n );\n }\n }\n }\n\n /**\n * Update section collapsed.\n *\n * @param {object} args\n * @param {object} args.element The leement to be expanded\n */\n _refreshSectionCollapsed({element}) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n if (!target) {\n throw new Error(`Unkown section with ID ${element.id}`);\n }\n // Check if it is already done.\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (element.isactive === isCollapsed) {\n this._expandSectionNode(element);\n }\n }\n\n /**\n * Expand a section node.\n *\n * By default the method will use element.isactive to decide if the\n * section is opened or closed. However, using forceValue it is possible\n * to open or close a section independant from the isactive attribute.\n *\n * @param {Object} element the course module state element\n * @param {boolean} forceValue optional forced expanded value\n */\n _expandSectionNode(element, forceValue) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n let collapsibleId = toggler.dataset.target ?? toggler.getAttribute(\"href\");\n if (!collapsibleId) {\n return;\n }\n collapsibleId = collapsibleId.replace('#', '');\n const collapsible = document.getElementById(collapsibleId);\n if (!collapsible) {\n return;\n }\n\n if (forceValue === undefined) {\n forceValue = (element.isactive) ? true : false;\n }\n\n // Course index is based on Bootstrap 4 collapsibles. To collapse them we need jQuery to\n // interact with collapsibles methods. Hopefully, this will change in Bootstrap 5 because\n // it does not require jQuery anymore.\n const togglerValue = (forceValue) ? 'show' : 'hide';\n jQuery(collapsible).collapse(togglerValue);\n }\n\n /**\n * Create a newcm instance.\n *\n * @param {object} param\n * @param {Object} param.state\n * @param {Object} param.element\n */\n async _createCm({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('li');\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n this.cms[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshSectionCmlist({\n state,\n element: state.section.get(element.sectionid),\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.cm(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'core_courseformat/local/courseindex/cm', data);\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.cms[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n }\n\n /**\n * Create a new section instance.\n *\n * @param {Object} details the update details.\n * @param {Object} details.state the state data.\n * @param {Object} details.element the element data.\n */\n async _createSection({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('div');\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n this.sections[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshCourseSectionlist({\n state,\n element: state.course,\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.section(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'core_courseformat/local/courseindex/section', data);\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.sections[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n }\n\n /**\n * Refresh a section cm list.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _refreshSectionCmlist({element}) {\n const cmlist = element.cmlist ?? [];\n const listparent = this.getElement(this.selectors.SECTION_CMLIST, element.id);\n this._fixOrder(listparent, cmlist, this.cms);\n }\n\n /**\n * Refresh the section list.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _refreshCourseSectionlist({element}) {\n const sectionlist = element.sectionlist ?? [];\n this._fixOrder(this.element, sectionlist, this.sections);\n }\n\n /**\n * Fix/reorder the section or cms order.\n *\n * @param {Element} container the HTML element to reorder.\n * @param {Array} neworder an array with the ids order\n * @param {Array} allitems the list of html elements that can be placed in the container\n */\n _fixOrder(container, neworder, allitems) {\n\n // Empty lists should not be visible.\n if (!neworder.length) {\n container.classList.add('hidden');\n container.innerHTML = '';\n return;\n }\n\n // Grant the list is visible (in case it was empty).\n container.classList.remove('hidden');\n\n // Move the elements in order at the beginning of the list.\n neworder.forEach((itemid, index) => {\n const item = allitems[itemid];\n // Get the current element at that position.\n const currentitem = container.children[index];\n if (currentitem === undefined) {\n container.append(item);\n return;\n }\n if (currentitem !== item) {\n container.insertBefore(item, currentitem);\n }\n });\n // Remove the remaining elements.\n while (container.children.length > neworder.length) {\n container.removeChild(container.lastChild);\n }\n }\n\n /**\n * Remove a cm from the list.\n *\n * The actual DOM element removal is delegated to the cm component.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _deleteCm({element}) {\n delete this.cms[element.id];\n }\n\n /**\n * Remove a section from the list.\n *\n * The actual DOM element removal is delegated to the section component.\n *\n * @param {Object} details the update details.\n * @param {Object} details.element the element data.\n */\n _deleteSection({element}) {\n delete this.sections[element.id];\n }\n}\n"],"file":"courseindex.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/courseindex/courseindex.js"],"names":["Component","name","selectors","SECTION","SECTION_CMLIST","CM","TOGGLER","COLLAPSE","DRAWER","classes","SECTIONHIDDEN","CMHIDDEN","SECTIONCURRENT","COLLAPSED","SHOW","sections","cms","addEventListener","element","_sectionTogglers","getElements","forEach","section","dataset","id","cm","contentTree","ContentTree","reactive","isEditing","watch","handler","_refreshSectionCollapsed","_createCm","_deleteCm","_createSection","_deleteSection","_refreshCourseSectionlist","_refreshSectionCmlist","event","sectionlink","target","closest","isChevron","toggler","querySelector","isCollapsed","classList","contains","sectionId","getAttribute","dispatch","isactive","getElement","Error","_expandSectionNode","forceValue","collapsibleId","replace","collapsible","document","getElementById","togglerValue","collapse","state","fakeelement","createElement","add","innerHTML","get","sectionid","exporter","getExporter","data","renderComponent","newcomponent","newelement","parentNode","replaceChild","course","cmlist","listparent","_fixOrder","sectionlist","container","neworder","allitems","length","remove","itemid","index","item","currentitem","children","append","insertBefore","removeChild","lastChild","BaseComponent"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course index main component.\n *\n * @module core_courseformat/local/courseindex/courseindex\n * @class core_courseformat/local/courseindex/courseindex\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport jQuery from 'jquery';\nimport ContentTree from 'core_courseformat/local/courseeditor/contenttree';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'courseindex';\n // Default query selectors.\n this.selectors = {\n SECTION: `[data-for='section']`,\n SECTION_CMLIST: `[data-for='cmlist']`,\n CM: `[data-for='cm']`,\n TOGGLER: `[data-action=\"togglecourseindexsection\"]`,\n COLLAPSE: `[data-toggle=\"collapse\"]`,\n DRAWER: `.drawer`,\n };\n // Default classes to toggle on refresh.\n this.classes = {\n SECTIONHIDDEN: 'dimmed',\n CMHIDDEN: 'dimmed',\n SECTIONCURRENT: 'current',\n COLLAPSED: `collapsed`,\n SHOW: `show`,\n };\n // Arrays to keep cms and sections elements.\n this.sections = {};\n this.cms = {};\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new Component({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n */\n stateReady() {\n // Activate section togglers.\n this.addEventListener(this.element, 'click', this._sectionTogglers);\n\n // Get cms and sections elements.\n const sections = this.getElements(this.selectors.SECTION);\n sections.forEach((section) => {\n this.sections[section.dataset.id] = section;\n });\n const cms = this.getElements(this.selectors.CM);\n cms.forEach((cm) => {\n this.cms[cm.dataset.id] = cm;\n });\n\n // Configure Aria Tree.\n this.contentTree = new ContentTree(this.element, this.selectors, this.reactive.isEditing);\n }\n\n getWatchers() {\n return [\n {watch: `section.isactive:updated`, handler: this._refreshSectionCollapsed},\n {watch: `cm:created`, handler: this._createCm},\n {watch: `cm:deleted`, handler: this._deleteCm},\n {watch: `section:created`, handler: this._createSection},\n {watch: `section:deleted`, handler: this._deleteSection},\n // Sections and cm sorting.\n {watch: `course.sectionlist:updated`, handler: this._refreshCourseSectionlist},\n {watch: `section.cmlist:updated`, handler: this._refreshSectionCmlist},\n ];\n }\n\n /**\n * Setup sections toggler.\n *\n * Toggler click is delegated to the main course index element because new sections can\n * appear at any moment and this way we prevent accidental double bindings.\n *\n * @param {Event} event the triggered event\n */\n _sectionTogglers(event) {\n const sectionlink = event.target.closest(this.selectors.TOGGLER);\n const isChevron = event.target.closest(this.selectors.COLLAPSE);\n\n if (sectionlink || isChevron) {\n\n const section = event.target.closest(this.selectors.SECTION);\n const toggler = section.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (isChevron || isCollapsed) {\n // Update the state.\n const sectionId = section.getAttribute('data-id');\n this.reactive.dispatch(\n 'sectionPreferences',\n [sectionId],\n {\n isactive: isCollapsed,\n },\n );\n }\n }\n }\n\n /**\n * Update section collapsed.\n *\n * @param {object} args\n * @param {object} args.element The leement to be expanded\n */\n _refreshSectionCollapsed({element}) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n if (!target) {\n throw new Error(`Unkown section with ID ${element.id}`);\n }\n // Check if it is already done.\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (element.isactive === isCollapsed) {\n this._expandSectionNode(element);\n }\n }\n\n /**\n * Expand a section node.\n *\n * By default the method will use element.isactive to decide if the\n * section is opened or closed. However, using forceValue it is possible\n * to open or close a section independant from the isactive attribute.\n *\n * @param {Object} element the course module state element\n * @param {boolean} forceValue optional forced expanded value\n */\n _expandSectionNode(element, forceValue) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n let collapsibleId = toggler.dataset.target ?? toggler.getAttribute(\"href\");\n if (!collapsibleId) {\n return;\n }\n collapsibleId = collapsibleId.replace('#', '');\n const collapsible = document.getElementById(collapsibleId);\n if (!collapsible) {\n return;\n }\n\n if (forceValue === undefined) {\n forceValue = (element.isactive) ? true : false;\n }\n\n // Course index is based on Bootstrap 4 collapsibles. To collapse them we need jQuery to\n // interact with collapsibles methods. Hopefully, this will change in Bootstrap 5 because\n // it does not require jQuery anymore (when MDL-79179 is integrated).\n const togglerValue = (forceValue) ? 'show' : 'hide';\n jQuery(collapsible).collapse(togglerValue);\n }\n\n /**\n * Create a newcm instance.\n *\n * @param {object} param\n * @param {Object} param.state\n * @param {Object} param.element\n */\n async _createCm({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('li');\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n this.cms[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshSectionCmlist({\n state,\n element: state.section.get(element.sectionid),\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.cm(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'core_courseformat/local/courseindex/cm', data);\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.cms[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n }\n\n /**\n * Create a new section instance.\n *\n * @param {Object} details the update details.\n * @param {Object} details.state the state data.\n * @param {Object} details.element the element data.\n */\n async _createSection({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('div');\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n this.sections[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshCourseSectionlist({\n state,\n element: state.course,\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.section(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'core_courseformat/local/courseindex/section', data);\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.sections[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n }\n\n /**\n * Refresh a section cm list.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _refreshSectionCmlist({element}) {\n const cmlist = element.cmlist ?? [];\n const listparent = this.getElement(this.selectors.SECTION_CMLIST, element.id);\n this._fixOrder(listparent, cmlist, this.cms);\n }\n\n /**\n * Refresh the section list.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _refreshCourseSectionlist({element}) {\n const sectionlist = element.sectionlist ?? [];\n this._fixOrder(this.element, sectionlist, this.sections);\n }\n\n /**\n * Fix/reorder the section or cms order.\n *\n * @param {Element} container the HTML element to reorder.\n * @param {Array} neworder an array with the ids order\n * @param {Array} allitems the list of html elements that can be placed in the container\n */\n _fixOrder(container, neworder, allitems) {\n\n // Empty lists should not be visible.\n if (!neworder.length) {\n container.classList.add('hidden');\n container.innerHTML = '';\n return;\n }\n\n // Grant the list is visible (in case it was empty).\n container.classList.remove('hidden');\n\n // Move the elements in order at the beginning of the list.\n neworder.forEach((itemid, index) => {\n const item = allitems[itemid];\n // Get the current element at that position.\n const currentitem = container.children[index];\n if (currentitem === undefined) {\n container.append(item);\n return;\n }\n if (currentitem !== item) {\n container.insertBefore(item, currentitem);\n }\n });\n // Remove the remaining elements.\n while (container.children.length > neworder.length) {\n container.removeChild(container.lastChild);\n }\n }\n\n /**\n * Remove a cm from the list.\n *\n * The actual DOM element removal is delegated to the cm component.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _deleteCm({element}) {\n delete this.cms[element.id];\n }\n\n /**\n * Remove a section from the list.\n *\n * The actual DOM element removal is delegated to the section component.\n *\n * @param {Object} details the update details.\n * @param {Object} details.element the element data.\n */\n _deleteSection({element}) {\n delete this.sections[element.id];\n }\n}\n"],"file":"courseindex.min.js"} \ No newline at end of file diff --git a/course/format/amd/build/local/courseindex/keyboardnav.min.js b/course/format/amd/build/local/courseindex/keyboardnav.min.js deleted file mode 100644 index ae1d0a8e783..00000000000 --- a/course/format/amd/build/local/courseindex/keyboardnav.min.js +++ /dev/null @@ -1,2 +0,0 @@ -define ("core_courseformat/local/courseindex/keyboardnav",["exports","jquery","core/tree"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=d(b);c=d(c);function d(a){return a&&a.__esModule?a:{default:a}}function e(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){e=function(a){return typeof a}}else{e=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return e(a)}function f(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function g(a,b){for(var c=0,d;c.\n\n/**\n * Course index keyboard navigation and aria-tree compatibility.\n *\n * Node tree and bootstrap collapsibles don't use the same HTML structure. However,\n * all keybindings and logic is compatible. This class translate the primitive opetations\n * to a bootstrap collapsible structure.\n *\n * @module core_courseformat/local/courseindex/keyboardnav\n * @class core_courseformat/local/courseindex/keyboardnav\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n// The core/tree uses jQuery to expand all nodes.\nimport $ from 'jquery';\nimport Tree from 'core/tree';\n\nexport default class extends Tree {\n\n /**\n * Setup the core/tree keyboard navigation.\n *\n * @param {CourseIndex} parent the parent component\n */\n constructor(parent) {\n // Init this value with the parent DOM element.\n super(parent.element);\n\n // Get selectors from parent.\n this.selectors = parent.selectors;\n\n // The core/tree library saves the visible elements cache inside the main tree node.\n // However, in edit mode content can change suddenly so we need to refresh caches when needed.\n if (parent.reactive.isEditing) {\n this._getVisibleItems = this.getVisibleItems;\n this.getVisibleItems = () => {\n this.refreshVisibleItemsCache();\n return this._getVisibleItems();\n };\n }\n // Add jQuery events to detect boostrap collapse and uncollapse.\n this.treeRoot.on('hidden.bs.collapse shown.bs.collapse', () => {\n this.refreshVisibleItemsCache();\n });\n // Register a custom callback for pressing enter key.\n this.registerEnterCallback(this.enterCallback.bind(this));\n }\n\n /**\n * Return the current active node.\n *\n * @return {Element|undefined} the active item if any\n */\n getActiveItem() {\n const activeItem = this.treeRoot.data('activeItem');\n if (activeItem) {\n return activeItem.get(0);\n }\n return undefined;\n }\n\n /**\n * Handle enter key on a collpasible node.\n *\n * @param {JQuery} item the jQuery object\n */\n enterCallback(item) {\n if (this.isGroupItem(item)) {\n // Group elements is like clicking a topic but without loosing the focus.\n window.location.href = item.find(this.selectors.TOGGLER).first().attr('href');\n item.find(this.selectors.TOGGLER).get(0).click();\n } else {\n // Activity links just follow the link href.\n window.location.href = item.find('a').first().attr('href');\n return;\n }\n }\n\n /**\n * Check if a gorup item is collapsed.\n *\n * @param {JQuery} item the jQuery object\n * @returns {boolean} if the element is collapsed\n */\n isGroupCollapsed(item) {\n const toggler = item.find(`[aria-expanded]`);\n return toggler.attr('aria-expanded') === 'false';\n }\n\n /**\n * Toggle a group item.\n *\n * @param {JQuery} item the jQuery object\n */\n toggleGroup(item) {\n const toggler = item.find(this.selectors.COLLAPSE);\n let collapsibleId = toggler.data('target') ?? toggler.attr('href');\n if (!collapsibleId) {\n return;\n }\n collapsibleId = collapsibleId.replace('#', '');\n\n // Bootstrap 4 uses jQuery to interact with collapsibles.\n $(`#${collapsibleId}`).collapse('toggle');\n }\n\n /**\n * Expand a group item.\n *\n * @param {JQuery} item the jQuery object\n */\n expandGroup(item) {\n if (this.isGroupCollapsed(item)) {\n this.toggleGroup(item);\n }\n }\n\n /**\n * Collpase a group item.\n *\n * @param {JQuery} item the jQuery object\n */\n collapseGroup(item) {\n if (!this.isGroupCollapsed(item)) {\n this.toggleGroup(item);\n }\n }\n\n /**\n * Expand all groups.\n */\n expandAllGroups() {\n const togglers = this.treeRoot.find(this.selectors.SECTION);\n togglers.each((index, item) => {\n this.expandGroup($(item));\n });\n }\n}\n"],"file":"keyboardnav.min.js"} \ No newline at end of file diff --git a/course/format/amd/src/local/content/actions.js b/course/format/amd/src/local/content/actions.js index d249a8164ed..9d930cacac2 100644 --- a/course/format/amd/src/local/content/actions.js +++ b/course/format/amd/src/local/content/actions.js @@ -33,6 +33,10 @@ import {prefetchStrings} from 'core/prefetch'; import {get_string as getString} from 'core/str'; import {getList} from 'core/normalise'; import * as CourseEvents from 'core_course/events'; +import Pending from 'core/pending'; +import ContentTree from 'core_courseformat/local/courseeditor/contenttree'; +// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-79179 is integrated. +import jQuery from 'jquery'; // Load global strings. prefetchStrings('core', ['movecoursesection', 'movecoursemodule', 'confirm', 'delete']); @@ -48,11 +52,15 @@ export default class extends BaseComponent { // Default query selectors. this.selectors = { ACTIONLINK: `[data-action]`, + // Move modal selectors. SECTIONLINK: `[data-for='section']`, CMLINK: `[data-for='cm']`, SECTIONNODE: `[data-for='sectionnode']`, - TOGGLER: `[data-toggle='collapse']`, + MODALTOGGLER: `[data-toggle='collapse']`, ADDSECTION: `[data-action='addSection']`, + CONTENTTREE: `#destination-selector`, + ACTIONMENU: `.action-menu`, + ACTIONMENUTOGGLER: `[data-toggle="dropdown"]`, }; // Component css classes. this.classes = { @@ -145,6 +153,9 @@ export default class extends BaseComponent { event.preventDefault(); + // The section edit menu to refocus on end. + const editTools = this._getClosestActionMenuToogler(target); + // Collect section information from the state. const exporter = this.reactive.getExporter(); const data = exporter.course(this.reactive.state); @@ -170,6 +181,17 @@ export default class extends BaseComponent { const generalSection = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-number='0']`); this._disableLink(generalSection); + // Setup keyboard navigation. + new ContentTree( + modalBody.querySelector(this.selectors.CONTENTTREE), + { + SECTION: this.selectors.SECTIONNODE, + TOGGLER: this.selectors.MODALTOGGLER, + COLLAPSE: this.selectors.MODALTOGGLER, + }, + true + ); + // Capture click. modalBody.addEventListener('click', (event) => { const target = event.target; @@ -181,7 +203,7 @@ export default class extends BaseComponent { } event.preventDefault(); this.reactive.dispatch('sectionMove', [sectionId], target.dataset.id); - modal.destroy(); + this._destroyModal(modal, editTools); }); } @@ -201,6 +223,9 @@ export default class extends BaseComponent { event.preventDefault(); + // The section edit menu to refocus on end. + const editTools = this._getClosestActionMenuToogler(target); + // Collect section information from the state. const exporter = this.reactive.getExporter(); const data = exporter.course(this.reactive.state); @@ -224,8 +249,27 @@ export default class extends BaseComponent { let currentElement = modalBody.querySelector(`${this.selectors.CMLINK}[data-id='${cmId}']`); this._disableLink(currentElement); - // Open the cm section node if possible. - currentElement.closest(this.selectors.SECTIONNODE)?.querySelector(this.selectors.TOGGLER)?.click(); + // Setup keyboard navigation. + new ContentTree( + modalBody.querySelector(this.selectors.CONTENTTREE), + { + SECTION: this.selectors.SECTIONNODE, + TOGGLER: this.selectors.MODALTOGGLER, + COLLAPSE: this.selectors.MODALTOGGLER, + ENTER: this.selectors.SECTIONLINK, + } + ); + + // Open the cm section node if possible (Bootstrap 4 uses jQuery to interact with collapsibles). + // All jQuery int this code can be replaced when MDL-79179 is integrated. + const sectionnode = currentElement.closest(this.selectors.SECTIONNODE); + const toggler = jQuery(sectionnode).find(this.selectors.MODALTOGGLER); + let collapsibleId = toggler.data('target') ?? toggler.attr('href'); + if (collapsibleId) { + // We cannot be sure we have # in the id element name. + collapsibleId = collapsibleId.replace('#', ''); + jQuery(`#${collapsibleId}`).collapse('toggle'); + } // Capture click. modalBody.addEventListener('click', (event) => { @@ -252,7 +296,7 @@ export default class extends BaseComponent { } this.reactive.dispatch('cmMove', [cmId], targetSectionId, targetCmId); - modal.destroy(); + this._destroyModal(modal, editTools); }); } @@ -349,6 +393,7 @@ export default class extends BaseComponent { _modalBodyRenderedPromise(modalParams) { return new Promise((resolve, reject) => { ModalFactory.create(modalParams).then((modal) => { + modal.setRemoveOnClose(true); // Handle body loading event. modal.getRoot().on(ModalEvents.bodyRendered, () => { resolve(modal); @@ -364,4 +409,38 @@ export default class extends BaseComponent { }); }); } + + /** + * Hide and later destroy a modal. + * + * Behat will fail if we remove the modal while some boostrap collapse is executing. + * + * @param {Modal} modal + * @param {HTMLElement} element the dom element to focus on. + */ + _destroyModal(modal, element) { + modal.hide(); + const pendingDestroy = new Pending(`courseformat/actions:destroyModal`); + if (element) { + element.focus(); + } + setTimeout(() =>{ + modal.destroy(); + pendingDestroy.resolve(); + }, 500); + } + + /** + * Get the closest actions menu toggler to an action element. + * + * @param {HTMLElement} element the action link element + * @returns {HTMLElement|undefined} + */ + _getClosestActionMenuToogler(element) { + const actionMenu = element.closest(this.selectors.ACTIONMENU); + if (!actionMenu) { + return undefined; + } + return actionMenu.querySelector(this.selectors.ACTIONMENUTOGGLER); + } } diff --git a/course/format/amd/src/local/courseindex/keyboardnav.js b/course/format/amd/src/local/courseeditor/contenttree.js similarity index 64% rename from course/format/amd/src/local/courseindex/keyboardnav.js rename to course/format/amd/src/local/courseeditor/contenttree.js index 1db75752400..1eff17f9b7d 100644 --- a/course/format/amd/src/local/courseindex/keyboardnav.js +++ b/course/format/amd/src/local/courseeditor/contenttree.js @@ -27,33 +27,41 @@ */ // The core/tree uses jQuery to expand all nodes. -import $ from 'jquery'; +import jQuery from 'jquery'; import Tree from 'core/tree'; +import {getList} from 'core/normalise'; export default class extends Tree { /** * Setup the core/tree keyboard navigation. * - * @param {CourseIndex} parent the parent component + * @param {Element|undefined} mainElement an alternative main element in case it is not from the parent component + * @param {Object|undefined} selectors alternative selectors + * @param {boolean} preventcache if the elements cache must be disabled. */ - constructor(parent) { + constructor(mainElement, selectors, preventcache) { // Init this value with the parent DOM element. - super(parent.element); + super(mainElement); // Get selectors from parent. - this.selectors = parent.selectors; + this.selectors = { + SECTION: selectors.SECTION, + TOGGLER: selectors.TOGGLER, + COLLAPSE: selectors.COLLAPSE, + ENTER: selectors.ENTER ?? selectors.TOGGLER, + }; // The core/tree library saves the visible elements cache inside the main tree node. // However, in edit mode content can change suddenly so we need to refresh caches when needed. - if (parent.reactive.isEditing) { + if (preventcache) { this._getVisibleItems = this.getVisibleItems; this.getVisibleItems = () => { this.refreshVisibleItemsCache(); return this._getVisibleItems(); }; } - // Add jQuery events to detect boostrap collapse and uncollapse. + // All jQuery events can be replaced when MDL-79179 is integrated. this.treeRoot.on('hidden.bs.collapse shown.bs.collapse', () => { this.refreshVisibleItemsCache(); }); @@ -69,7 +77,7 @@ export default class extends Tree { getActiveItem() { const activeItem = this.treeRoot.data('activeItem'); if (activeItem) { - return activeItem.get(0); + return getList(activeItem)[0]; } return undefined; } @@ -77,16 +85,25 @@ export default class extends Tree { /** * Handle enter key on a collpasible node. * - * @param {JQuery} item the jQuery object + * @param {JQuery} jQueryItem the jQuery object */ - enterCallback(item) { - if (this.isGroupItem(item)) { + enterCallback(jQueryItem) { + const item = getList(jQueryItem)[0]; + if (this.isGroupItem(jQueryItem)) { // Group elements is like clicking a topic but without loosing the focus. - window.location.href = item.find(this.selectors.TOGGLER).first().attr('href'); - item.find(this.selectors.TOGGLER).get(0).click(); + const enter = item.querySelector(this.selectors.ENTER); + if (enter.getAttribute('href') !== '#') { + window.location.href = enter.getAttribute('href'); + } + enter.click(); } else { // Activity links just follow the link href. - window.location.href = item.find('a').first().attr('href'); + const link = item.querySelector('a'); + if (link.getAttribute('href') !== '#') { + window.location.href = link.getAttribute('href'); + } else { + link.click(); + } return; } } @@ -94,12 +111,13 @@ export default class extends Tree { /** * Check if a gorup item is collapsed. * - * @param {JQuery} item the jQuery object + * @param {JQuery} jQueryItem the jQuery object * @returns {boolean} if the element is collapsed */ - isGroupCollapsed(item) { - const toggler = item.find(`[aria-expanded]`); - return toggler.attr('aria-expanded') === 'false'; + isGroupCollapsed(jQueryItem) { + const item = getList(jQueryItem)[0]; + const toggler = item.querySelector(`[aria-expanded]`); + return toggler.getAttribute('aria-expanded') === 'false'; } /** @@ -108,6 +126,7 @@ export default class extends Tree { * @param {JQuery} item the jQuery object */ toggleGroup(item) { + // All jQuery in this segment of code can be replaced when MDL-79179 is integrated. const toggler = item.find(this.selectors.COLLAPSE); let collapsibleId = toggler.data('target') ?? toggler.attr('href'); if (!collapsibleId) { @@ -116,7 +135,10 @@ export default class extends Tree { collapsibleId = collapsibleId.replace('#', ''); // Bootstrap 4 uses jQuery to interact with collapsibles. - $(`#${collapsibleId}`).collapse('toggle'); + const collapsible = jQuery(`#${collapsibleId}`); + if (collapsible.length) { + jQuery(`#${collapsibleId}`).collapse('toggle'); + } } /** @@ -145,9 +167,9 @@ export default class extends Tree { * Expand all groups. */ expandAllGroups() { - const togglers = this.treeRoot.find(this.selectors.SECTION); - togglers.each((index, item) => { - this.expandGroup($(item)); + const togglers = getList(this.treeRoot)[0].querySelectorAll(this.selectors.SECTION); + togglers.forEach(item => { + this.expandGroup(jQuery(item)); }); } } diff --git a/course/format/amd/src/local/courseindex/courseindex.js b/course/format/amd/src/local/courseindex/courseindex.js index 65bcdf60f19..c562034cd17 100644 --- a/course/format/amd/src/local/courseindex/courseindex.js +++ b/course/format/amd/src/local/courseindex/courseindex.js @@ -25,7 +25,7 @@ import {BaseComponent} from 'core/reactive'; import {getCurrentCourseEditor} from 'core_courseformat/courseeditor'; import jQuery from 'jquery'; -import TreeNav from 'core_courseformat/local/courseindex/keyboardnav'; +import ContentTree from 'core_courseformat/local/courseeditor/contenttree'; export default class Component extends BaseComponent { @@ -90,7 +90,7 @@ export default class Component extends BaseComponent { }); // Configure Aria Tree. - this.treeNav = new TreeNav(this); + this.contentTree = new ContentTree(this.element, this.selectors, this.reactive.isEditing); } getWatchers() { @@ -187,7 +187,7 @@ export default class Component extends BaseComponent { // Course index is based on Bootstrap 4 collapsibles. To collapse them we need jQuery to // interact with collapsibles methods. Hopefully, this will change in Bootstrap 5 because - // it does not require jQuery anymore. + // it does not require jQuery anymore (when MDL-79179 is integrated). const togglerValue = (forceValue) ? 'show' : 'hide'; jQuery(collapsible).collapse(togglerValue); } diff --git a/course/format/templates/local/content/movecm.mustache b/course/format/templates/local/content/movecm.mustache index a913662f68d..308c13551d5 100644 --- a/course/format/templates/local/content/movecm.mustache +++ b/course/format/templates/local/content/movecm.mustache @@ -77,9 +77,11 @@ }}

{{#str}} movefull, moodle, {{cmname}} {{/str}}:

-