diff --git a/course/amd/build/actions.min.js b/course/amd/build/actions.min.js index d93722dd68e..cb4575e9aa9 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);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()})})}}}); +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=a.get(0),c=M.util.add_lightbox(g,g.Node(b));if("section"==b.dataset.for&&b.dataset.id){p.dispatch("sectionLock",[b.dataset.id],!0);c.setAttribute("data-state","section");c.setAttribute("data-state-id",b.dataset.id)}c.show();return c},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();if(a.getAttribute("data-state")){p.dispatch("".concat(a.getAttribute("data-state"),"Lock"),[a.getAttribute("data-state-id")],!1)}},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}p.dispatch("cmLock",[f.id],!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 681509f9cb2..c4a15ba2651 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","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 +{"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","for","setAttribute","removeSpinner","delay","window","setTimeout","removeClass","hide","mutation","removeLightbox","getAttribute","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 const item = sectionelement.get(0);\n var lightbox = M.util.add_lightbox(Y, Y.Node(item));\n if (item.dataset.for == 'section' && item.dataset.id) {\n courseeditor.dispatch('sectionLock', [item.dataset.id], true);\n lightbox.setAttribute('data-state', 'section');\n lightbox.setAttribute('data-state-id', item.dataset.id);\n }\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 // Unlock state if necessary.\n if (lightbox.getAttribute('data-state')) {\n courseeditor.dispatch(\n `${lightbox.getAttribute('data-state')}Lock`,\n [lightbox.getAttribute('data-state-id')],\n false\n );\n }\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.\n courseeditor.dispatch('cmLock', [cm.id], true);\n\n // Now we do the real mutation.\n statemanager.setReadOnly(false);\n\n // This unlocked 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 491cde1e462..8be6d375288 100644 --- a/course/amd/src/actions.js +++ b/course/amd/src/actions.js @@ -201,7 +201,13 @@ define( * @returns {Node} */ var addSectionLightbox = function(sectionelement) { - var lightbox = M.util.add_lightbox(Y, Y.Node(sectionelement.get(0))); + const item = sectionelement.get(0); + var lightbox = M.util.add_lightbox(Y, Y.Node(item)); + if (item.dataset.for == 'section' && item.dataset.id) { + courseeditor.dispatch('sectionLock', [item.dataset.id], true); + lightbox.setAttribute('data-state', 'section'); + lightbox.setAttribute('data-state-id', item.dataset.id); + } lightbox.show(); return lightbox; }; @@ -237,6 +243,14 @@ define( if (lightbox) { window.setTimeout(function() { lightbox.hide(); + // Unlock state if necessary. + if (lightbox.getAttribute('data-state')) { + courseeditor.dispatch( + `${lightbox.getAttribute('data-state')}Lock`, + [lightbox.getAttribute('data-state-id')], + false + ); + } }, delay); } }; @@ -776,18 +790,13 @@ define( return; } - // Send the element is locked. Reactive events are only triggered when the state - // read only mode is restored. We want to notify the interface the element is - // locked so we need to do a quick lock operation before performing the rest - // of the mutation. - statemanager.setReadOnly(false); - cm.locked = true; - statemanager.setReadOnly(true); + // Send the element is locked. + courseeditor.dispatch('cmLock', [cm.id], true); // Now we do the real mutation. statemanager.setReadOnly(false); - // This locked will take effect when the read only is restored. + // This unlocked will take effect when the read only is restored. cm.locked = false; switch (action) { diff --git a/course/format/amd/build/local/content/section.min.js.map b/course/format/amd/build/local/content/section.min.js.map index 746de71467d..c5d9ab03907 100644 --- a/course/format/amd/build/local/content/section.min.js.map +++ b/course/format/amd/build/local/content/section.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../../src/local/content/section.js"],"names":["name","selectors","SECTION_ITEM","CM","classes","LOCKED","id","element","dataset","state","configState","reactive","isEditing","supportComponents","sectionItem","getElement","headerComponent","Header","fullregion","configDragDrop","watch","handler","_refreshSection","dropdata","type","sectionReturn","cms","getElements","length","classList","toggle","DRAGGING","dragging","locked","DndSection"],"mappings":"gQAwBA,OACA,O,60FAOa,CAEL,KAAKA,IAAL,CAAY,iBAAZ,CAEA,KAAKC,SAAL,CAAiB,CACbC,YAAY,6BADC,CAEbC,EAAE,wBAFW,CAAjB,CAKA,KAAKC,OAAL,CAAe,CACXC,MAAM,CAAE,gBADG,CAAf,CAKA,KAAKC,EAAL,CAAU,KAAKC,OAAL,CAAaC,OAAb,CAAqBF,EAClC,C,8CAOUG,C,CAAO,CACd,KAAKC,WAAL,CAAiBD,CAAjB,EAEA,GAAI,KAAKE,QAAL,CAAcC,SAAd,EAA2B,KAAKD,QAAL,CAAcE,iBAA7C,CAAgE,CAE5D,GAAMC,CAAAA,CAAW,CAAG,KAAKC,UAAL,CAAgB,KAAKd,SAAL,CAAeC,YAA/B,CAApB,CACA,GAAIY,CAAJ,CAAiB,CAEb,GAAME,CAAAA,CAAe,CAAG,GAAIC,UAAJ,MACjB,IADiB,EAEpBV,OAAO,CAAEO,CAFW,CAGpBI,UAAU,CAAE,KAAKX,OAHG,GAAxB,CAKA,KAAKY,cAAL,CAAoBH,CAApB,CACH,CACJ,CACJ,C,iDAOa,CACV,MAAO,CACH,CAACI,KAAK,mBAAa,KAAKd,EAAlB,aAAN,CAAuCe,OAAO,CAAE,KAAKC,eAArD,CADG,CAGV,C,0DAQeC,C,CAAU,CAEvB,GAAuB,SAAnB,WAAAA,CAAQ,WAARA,SAAAA,CAAQ,CAAEC,IAAV,GAA+D,CAA/B,OAAKb,QAAL,CAAcc,aAAlD,CAAsE,CACjE,QACH,CACD,2DAA8BF,CAA9B,CACH,C,6CAOW,CACR,GAAMG,CAAAA,CAAG,CAAG,KAAKC,WAAL,CAAiB,KAAK1B,SAAL,CAAeE,EAAhC,CAAZ,CAEA,GAAI,CAACuB,CAAD,EAAuB,CAAf,GAAAA,CAAG,CAACE,MAAhB,CAA8B,CAC1B,MAAO,KACV,CACD,MAAOF,CAAAA,CAAG,CAACA,CAAG,CAACE,MAAJ,CAAa,CAAd,CACb,C,0DAQ0B,SAAVrB,CAAU,GAAVA,OAAU,CAEvB,KAAKA,OAAL,CAAasB,SAAb,CAAuBC,MAAvB,CAA8B,KAAK1B,OAAL,CAAa2B,QAA3C,WAAqDxB,CAAO,CAACyB,QAA7D,oBACA,KAAKzB,OAAL,CAAasB,SAAb,CAAuBC,MAAvB,CAA8B,KAAK1B,OAAL,CAAaC,MAA3C,WAAmDE,CAAO,CAAC0B,MAA3D,oBACA,KAAKA,MAAL,CAAc1B,CAAO,CAAC0B,MACzB,C,cA/FwBC,S","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 section format component.\n *\n * @module core_courseformat/local/content/section\n * @class core_courseformat/local/content/section\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Header from 'core_courseformat/local/content/section/header';\nimport DndSection from 'core_courseformat/local/courseeditor/dndsection';\n\nexport default class extends DndSection {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'content_section';\n // Default query selectors.\n this.selectors = {\n SECTION_ITEM: `[data-for='section_title']`,\n CM: `[data-for=\"cmitem\"]`,\n };\n // Most classes will be loaded later by DndCmItem.\n this.classes = {\n LOCKED: 'editinprogress',\n };\n\n // We need our id to watch specific events.\n this.id = this.element.dataset.id;\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the initial state\n */\n stateReady(state) {\n this.configState(state);\n // Drag and drop is only available for components compatible course formats.\n if (this.reactive.isEditing && this.reactive.supportComponents) {\n // Section zero and other formats sections may not have a title to drag.\n const sectionItem = this.getElement(this.selectors.SECTION_ITEM);\n if (sectionItem) {\n // Init the inner dragable element.\n const headerComponent = new Header({\n ...this,\n element: sectionItem,\n fullregion: this.element,\n });\n this.configDragDrop(headerComponent);\n }\n }\n }\n\n /**\n * Component watchers.\n *\n * @returns {Array} of watchers\n */\n getWatchers() {\n return [\n {watch: `section[${this.id}]:updated`, handler: this._refreshSection},\n ];\n }\n\n /**\n * Validate if the drop data can be dropped over the component.\n *\n * @param {Object} dropdata the exported drop data.\n * @returns {boolean}\n */\n validateDropData(dropdata) {\n // If the format uses one section per page sections dropping in the content is ignored.\n if (dropdata?.type === 'section' && this.reactive.sectionReturn != 0) {\n return false;\n }\n return super.validateDropData(dropdata);\n }\n\n /**\n * Get the last CM element of that section.\n *\n * @returns {element|null}\n */\n getLastCm() {\n const cms = this.getElements(this.selectors.CM);\n // DndUpload may add extra elements so :last-child selector cannot be used.\n if (!cms || cms.length === 0) {\n return null;\n }\n return cms[cms.length - 1];\n }\n\n /**\n * Update a course index section using the state information.\n *\n * @param {object} param\n * @param {Object} param.element details the update details.\n */\n _refreshSection({element}) {\n // Update classes.\n this.element.classList.toggle(this.classes.DRAGGING, element.dragging ?? false);\n this.element.classList.toggle(this.classes.LOCKED, element.locked ?? false);\n this.locked = element.locked;\n }\n}\n"],"file":"section.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/content/section.js"],"names":["name","selectors","SECTION_ITEM","CM","classes","LOCKED","id","element","dataset","state","configState","reactive","isEditing","supportComponents","sectionItem","getElement","headerComponent","Header","fullregion","configDragDrop","watch","handler","_refreshSection","dropdata","type","sectionReturn","cms","getElements","length","classList","toggle","DRAGGING","dragging","locked","DndSection"],"mappings":"gQAwBA,OACA,O,60FAOa,CAEL,KAAKA,IAAL,CAAY,iBAAZ,CAEA,KAAKC,SAAL,CAAiB,CACbC,YAAY,6BADC,CAEbC,EAAE,wBAFW,CAAjB,CAKA,KAAKC,OAAL,CAAe,CACXC,MAAM,CAAE,gBADG,CAAf,CAKA,KAAKC,EAAL,CAAU,KAAKC,OAAL,CAAaC,OAAb,CAAqBF,EAClC,C,8CAOUG,C,CAAO,CACd,KAAKC,WAAL,CAAiBD,CAAjB,EAEA,GAAI,KAAKE,QAAL,CAAcC,SAAd,EAA2B,KAAKD,QAAL,CAAcE,iBAA7C,CAAgE,CAE5D,GAAMC,CAAAA,CAAW,CAAG,KAAKC,UAAL,CAAgB,KAAKd,SAAL,CAAeC,YAA/B,CAApB,CACA,GAAIY,CAAJ,CAAiB,CAEb,GAAME,CAAAA,CAAe,CAAG,GAAIC,UAAJ,MACjB,IADiB,EAEpBV,OAAO,CAAEO,CAFW,CAGpBI,UAAU,CAAE,KAAKX,OAHG,GAAxB,CAKA,KAAKY,cAAL,CAAoBH,CAApB,CACH,CACJ,CACJ,C,iDAOa,CACV,MAAO,CACH,CAACI,KAAK,mBAAa,KAAKd,EAAlB,aAAN,CAAuCe,OAAO,CAAE,KAAKC,eAArD,CADG,CAGV,C,0DAQgBC,C,CAAU,CAExB,GAAuB,SAAnB,WAAAA,CAAQ,WAARA,SAAAA,CAAQ,CAAEC,IAAV,GAA+D,CAA/B,OAAKb,QAAL,CAAcc,aAAlD,CAAsE,CACjE,QACH,CACD,2DAA8BF,CAA9B,CACH,C,6CAOW,CACR,GAAMG,CAAAA,CAAG,CAAG,KAAKC,WAAL,CAAiB,KAAK1B,SAAL,CAAeE,EAAhC,CAAZ,CAEA,GAAI,CAACuB,CAAD,EAAuB,CAAf,GAAAA,CAAG,CAACE,MAAhB,CAA8B,CAC1B,MAAO,KACV,CACD,MAAOF,CAAAA,CAAG,CAACA,CAAG,CAACE,MAAJ,CAAa,CAAd,CACb,C,0DAQ0B,SAAVrB,CAAU,GAAVA,OAAU,CAEvB,KAAKA,OAAL,CAAasB,SAAb,CAAuBC,MAAvB,CAA8B,KAAK1B,OAAL,CAAa2B,QAA3C,WAAqDxB,CAAO,CAACyB,QAA7D,oBACA,KAAKzB,OAAL,CAAasB,SAAb,CAAuBC,MAAvB,CAA8B,KAAK1B,OAAL,CAAaC,MAA3C,WAAmDE,CAAO,CAAC0B,MAA3D,oBACA,KAAKA,MAAL,CAAc1B,CAAO,CAAC0B,MACzB,C,cA/FwBC,S","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 section format component.\n *\n * @module core_courseformat/local/content/section\n * @class core_courseformat/local/content/section\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Header from 'core_courseformat/local/content/section/header';\nimport DndSection from 'core_courseformat/local/courseeditor/dndsection';\n\nexport default class extends DndSection {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'content_section';\n // Default query selectors.\n this.selectors = {\n SECTION_ITEM: `[data-for='section_title']`,\n CM: `[data-for=\"cmitem\"]`,\n };\n // Most classes will be loaded later by DndCmItem.\n this.classes = {\n LOCKED: 'editinprogress',\n };\n\n // We need our id to watch specific events.\n this.id = this.element.dataset.id;\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the initial state\n */\n stateReady(state) {\n this.configState(state);\n // Drag and drop is only available for components compatible course formats.\n if (this.reactive.isEditing && this.reactive.supportComponents) {\n // Section zero and other formats sections may not have a title to drag.\n const sectionItem = this.getElement(this.selectors.SECTION_ITEM);\n if (sectionItem) {\n // Init the inner dragable element.\n const headerComponent = new Header({\n ...this,\n element: sectionItem,\n fullregion: this.element,\n });\n this.configDragDrop(headerComponent);\n }\n }\n }\n\n /**\n * Component watchers.\n *\n * @returns {Array} of watchers\n */\n getWatchers() {\n return [\n {watch: `section[${this.id}]:updated`, handler: this._refreshSection},\n ];\n }\n\n /**\n * Validate if the drop data can be dropped over the component.\n *\n * @param {Object} dropdata the exported drop data.\n * @returns {boolean}\n */\n validateDropData(dropdata) {\n // If the format uses one section per page sections dropping in the content is ignored.\n if (dropdata?.type === 'section' && this.reactive.sectionReturn != 0) {\n return false;\n }\n return super.validateDropData(dropdata);\n }\n\n /**\n * Get the last CM element of that section.\n *\n * @returns {element|null}\n */\n getLastCm() {\n const cms = this.getElements(this.selectors.CM);\n // DndUpload may add extra elements so :last-child selector cannot be used.\n if (!cms || cms.length === 0) {\n return null;\n }\n return cms[cms.length - 1];\n }\n\n /**\n * Update a course index section using the state information.\n *\n * @param {object} param\n * @param {Object} param.element details the update details.\n */\n _refreshSection({element}) {\n // Update classes.\n this.element.classList.toggle(this.classes.DRAGGING, element.dragging ?? false);\n this.element.classList.toggle(this.classes.LOCKED, element.locked ?? false);\n this.locked = element.locked;\n }\n}\n"],"file":"section.min.js"} \ No newline at end of file diff --git a/course/format/amd/src/local/content/section.js b/course/format/amd/src/local/content/section.js index 362adf266e6..28de7c8d1ee 100644 --- a/course/format/amd/src/local/content/section.js +++ b/course/format/amd/src/local/content/section.js @@ -82,12 +82,12 @@ export default class extends DndSection { } /** - * Validate if the drop data can be dropped over the component. - * - * @param {Object} dropdata the exported drop data. - * @returns {boolean} - */ - validateDropData(dropdata) { + * Validate if the drop data can be dropped over the component. + * + * @param {Object} dropdata the exported drop data. + * @returns {boolean} + */ + validateDropData(dropdata) { // If the format uses one section per page sections dropping in the content is ignored. if (dropdata?.type === 'section' && this.reactive.sectionReturn != 0) { return false; diff --git a/lib/amd/build/local/reactive/basecomponent.min.js b/lib/amd/build/local/reactive/basecomponent.min.js index 229e16eea47..bffac768726 100644 --- a/lib/amd/build/local/reactive/basecomponent.min.js +++ b/lib/amd/build/local/reactive/basecomponent.min.js @@ -1,2 +1,2 @@ -define ("core/local/reactive/basecomponent",["exports","core/templates"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);function c(a,b){return h(a)||g(a,b)||e(a,b)||d()}function d(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function e(a,b){if(!a)return;if("string"==typeof a)return f(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return f(a,b)}function f(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);ca.length)b=a.length;for(var c=0,d=Array(b);c.\n\nimport Templates from 'core/templates';\n\n/**\n * Reactive UI component base class.\n *\n * Each UI reactive component should extend this class to interact with a reactive state.\n *\n * @module core/local/reactive/basecomponent\n * @class core/local/reactive/basecomponent\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default class {\n\n /**\n * The component descriptor data structure.\n *\n * This structure is used by any component and init method to define the way the component will interact\n * with the interface and whith reactive instance operates. The logic behind this object is to avoid\n * unnecessary dependancies between the final interface and the state logic.\n *\n * Any component interacts with a single main DOM element (description.element) but it can use internal\n * selector to select elements within this main element (descriptor.selectors). By default each component\n * will provide it's own default selectors, but those can be overridden by the \"descriptor.selectors\"\n * property in case the mustache wants to reuse the same component logic but with a different interface.\n *\n * @typedef {object} descriptor\n * @property {Reactive} reactive an optional reactive module to register in\n * @property {DOMElement} element all components needs an element to anchor events\n * @property {object} [selectors] an optional object to override query selectors\n */\n\n /**\n * The class constructor.\n *\n * The only param this method gets is a constructor with all the mandatory\n * and optional component data. Component will receive the same descriptor\n * as create method param.\n *\n * This method will call the \"create\" method before registering the component into\n * the reactive module. This way any component can add default selectors and events.\n *\n * @param {descriptor} descriptor data to create the object.\n */\n constructor(descriptor) {\n\n if (descriptor.element === undefined || !(descriptor.element instanceof HTMLElement)) {\n throw Error(`Reactive components needs a main DOM element to dispatch events`);\n }\n\n this.element = descriptor.element;\n\n // Variable to track event listeners.\n this.eventHandlers = new Map([]);\n this.eventListeners = [];\n\n // Empty default component selectors.\n this.selectors = {};\n\n // Empty default event list from the static method.\n this.events = this.constructor.getEvents();\n\n // Call create function to get the component defaults.\n this.create(descriptor);\n\n // Overwrite the components selectors if necessary.\n if (descriptor.selectors !== undefined) {\n this.addSelectors(descriptor.selectors);\n }\n\n // Register into a reactive instance.\n if (descriptor.reactive === undefined) {\n // Ask parent components for registration.\n this.element.dispatchEvent(new CustomEvent(\n 'core/reactive:requestRegistration',\n {\n bubbles: true,\n detail: {component: this},\n }\n ));\n } else {\n this.reactive = descriptor.reactive;\n this.reactive.registerComponent(this);\n // Add a listener to register child components.\n this.addEventListener(\n this.element,\n 'core/reactive:requestRegistration',\n (event) => {\n if (event?.detail?.component) {\n event.stopPropagation();\n this.registerChildComponent(event.detail.component);\n }\n }\n );\n }\n }\n\n /**\n * Return the component custom event names.\n *\n * Components may override this method to provide their own events.\n *\n * Component custom events is an important part of component reusability. This function\n * is static because is part of the component definition and should be accessible from\n * outsite the instances. However, values will be available at instance level in the\n * this.events object.\n *\n * @returns {Object} the component events.\n */\n static getEvents() {\n return {};\n }\n\n /**\n * Component create function.\n *\n * Default init method will call \"create\" when all internal attributes are set\n * but before the component is not yet registered in the reactive module.\n *\n * In this method any component can define its own defaults such as:\n * - this.selectors {object} the default query selectors of this component.\n * - this.events {object} a list of event names this component dispatch\n * - extract any data from the main dom element (this.element)\n * - set any other data the component uses\n *\n * @param {descriptor} descriptor the component descriptor\n */\n // eslint-disable-next-line no-unused-vars\n create(descriptor) {\n // Components may override this method to initialize selects, events or other data.\n }\n\n /**\n * Component destroy hook.\n *\n * BaseComponent call this method when a component is unregistered or removed.\n *\n * Components may override this method to clean the HTML or do some action when the\n * component is unregistered or removed.\n */\n destroy() {\n // Components can override this method.\n }\n\n /**\n * Return the list of watchers that component has.\n *\n * Each watcher is represented by an object with two attributes:\n * - watch (string) the specific state event to watch. Example 'section.visible:updated'\n * - handler (function) the function to call when the watching state change happens\n *\n * Any component shoudl override this method to define their state watchers.\n *\n * @returns {array} array of watchers.\n */\n getWatchers() {\n return [];\n }\n\n /**\n * Reactive module will call this method when the state is ready.\n *\n * Component can override this method to update/load the component HTML or to bind\n * listeners to HTML entities.\n */\n stateReady() {\n // Components can override this method.\n }\n\n /**\n * Get the main DOM element of this component or a subelement.\n *\n * @param {string|undefined} query optional subelement query\n * @param {string|undefined} dataId optional data-id value\n * @returns {element|undefined} the DOM element (if any)\n */\n getElement(query, dataId) {\n if (query === undefined && dataId === undefined) {\n return this.element;\n }\n const dataSelector = (dataId) ? `[data-id='${dataId}']` : '';\n const selector = `${query ?? ''}${dataSelector}`;\n return this.element.querySelector(selector);\n }\n\n /**\n * Get the all subelement that match a query selector.\n *\n * @param {string|undefined} query optional subelement query\n * @param {string|undefined} dataId optional data-id value\n * @returns {NodeList} the DOM elements\n */\n getElements(query, dataId) {\n const dataSelector = (dataId) ? `[data-id='${dataId}']` : '';\n const selector = `${query ?? ''}${dataSelector}`;\n return this.element.querySelectorAll(selector);\n }\n\n /**\n * Add or update the component selectors.\n *\n * @param {Object} newSelectors an object of new selectors.\n */\n addSelectors(newSelectors) {\n for (const [selectorName, selector] of Object.entries(newSelectors)) {\n this.selectors[selectorName] = selector;\n }\n }\n\n /**\n * Return a component selector.\n *\n * @param {string} selectorName the selector name\n * @return {string|undefined} the query selector\n */\n getSelector(selectorName) {\n return this.selectors[selectorName];\n }\n\n /**\n * Dispatch a custom event on this.element.\n *\n * This is just a convenient method to dispatch custom events from within a component.\n * Components are free to use an alternative function to dispatch custom\n * events. The only restriction is that it should be dispatched on this.element\n * and specify \"bubbles:true\" to alert any component listeners.\n *\n * @param {string} eventName the event name\n * @param {*} detail event detail data\n */\n dispatchEvent(eventName, detail) {\n this.element.dispatchEvent(new CustomEvent(eventName, {\n bubbles: true,\n detail: detail,\n }));\n }\n\n /**\n * Render a new Component using a mustache file.\n *\n * It is important to note that this method should NOT be used for loading regular mustache files\n * as it returns a Promise that will only be resolved if the mustache registers a component instance.\n *\n * @param {element} target the DOM element that contains the component\n * @param {string} file the component mustache file to render\n * @param {*} data the mustache data\n * @return {Promise} a promise of the resulting component instance\n */\n renderComponent(target, file, data) {\n return new Promise((resolve, reject) => {\n target.addEventListener('ComponentRegistration:Success', ({detail}) => {\n resolve(detail.component);\n });\n target.addEventListener('ComponentRegistration:Fail', () => {\n reject(`Registration of ${file} fails.`);\n });\n Templates.renderForPromise(\n file,\n data\n ).then(({html, js}) => {\n Templates.replaceNodeContents(target, html, js);\n return true;\n }).catch(error => {\n reject(`Rendering of ${file} throws an error.`);\n throw error;\n });\n });\n }\n\n /**\n * Add and bind an event listener to a target and keep track of all event listeners.\n *\n * The native element.addEventListener method is not object oriented friently as the\n * \"this\" represents the element that triggers the event and not the listener class.\n * As components can be unregister and removed at any time, the BaseComponent provides\n * this method to keep track of all component listeners and do all of the bind stuff.\n *\n * @param {Element} target the event target\n * @param {string} type the event name\n * @param {function} listener the class method that recieve the event\n */\n addEventListener(target, type, listener) {\n\n // Check if we have the bind version of that listener.\n let bindListener = this.eventHandlers.get(listener);\n\n if (bindListener === undefined) {\n bindListener = listener.bind(this);\n this.eventHandlers.set(listener, bindListener);\n }\n\n target.addEventListener(type, bindListener);\n\n // Keep track of all component event listeners in case we need to remove them.\n this.eventListeners.push({\n target,\n type,\n bindListener,\n });\n\n }\n\n /**\n * Remove an event listener from a component.\n *\n * This method allows components to remove listeners without keeping track of the\n * listeners bind versions of the method. Both addEventListener and removeEventListener\n * keeps internally the relation between the original class method and the bind one.\n *\n * @param {Element} target the event target\n * @param {string} type the event name\n * @param {function} listener the class method that recieve the event\n */\n removeEventListener(target, type, listener) {\n // Check if we have the bind version of that listener.\n let bindListener = this.eventHandlers.get(listener);\n\n if (bindListener === undefined) {\n // This listener has not been added.\n return;\n }\n\n target.removeEventListener(type, bindListener);\n }\n\n /**\n * Remove all event listeners from this component.\n *\n * This method is called also when the component is unregistered or removed.\n *\n * Note that only listeners registered with the addEventListener method\n * will be removed. Other manual listeners will keep active.\n */\n removeAllEventListeners() {\n this.eventListeners.forEach(({target, type, bindListener}) => {\n target.removeEventListener(type, bindListener);\n });\n this.eventListeners = [];\n }\n\n /**\n * Remove a previously rendered component instance.\n *\n * This method will remove the component HTML and unregister it from the\n * reactive module.\n */\n remove() {\n this.unregister();\n this.element.remove();\n }\n\n /**\n * Unregister the component from the reactive module.\n *\n * This method will disable the component logic, event listeners and watchers\n * but it won't remove any HTML created by the component. However, it will trigger\n * the destroy hook to allow the component to clean parts of the interface.\n */\n unregister() {\n this.reactive.unregisterComponent(this);\n this.removeAllEventListeners();\n this.destroy();\n }\n\n /**\n * Dispatch a component registration event to inform the parent node.\n *\n * The registration event is different from the rest of the component events because\n * is the only way in which components can communicate its existence to a possible parent.\n * Most components will be created by including a mustache file, child components\n * must emit a registration event to the parent DOM element to alert about the registration.\n */\n dispatchRegistrationSuccess() {\n // The registration event does not bubble because we just want to comunicate with the parentNode.\n // Otherwise, any component can get multiple registrations events and could not differentiate\n // between child components and grand child components.\n if (this.element.parentNode === undefined) {\n return;\n }\n // This custom element is captured by renderComponent method.\n this.element.parentNode.dispatchEvent(new CustomEvent(\n 'ComponentRegistration:Success',\n {\n bubbles: false,\n detail: {component: this},\n }\n ));\n }\n\n /**\n * Dispatch a component registration fail event to inform the parent node.\n *\n * As dispatchRegistrationSuccess, this method will communicate the registration fail to the\n * parent node to inform the possible parent component.\n */\n dispatchRegistrationFail() {\n if (this.element.parentNode === undefined) {\n return;\n }\n // This custom element is captured only by renderComponent method.\n this.element.parentNode.dispatchEvent(new CustomEvent(\n 'ComponentRegistration:Fail',\n {\n bubbles: false,\n detail: {component: this},\n }\n ));\n }\n\n /**\n * Register a child component into the reactive instance.\n *\n * @param {self} component the component to register.\n */\n registerChildComponent(component) {\n component.reactive = this.reactive;\n this.reactive.registerComponent(component);\n }\n\n /**\n * Set the lock value and locks or unlocks the element.\n *\n * @param {boolean} locked the new locked value\n */\n set locked(locked) {\n this.setElementLocked(this.element, locked);\n }\n\n /**\n * Get the current locked value from the element.\n *\n * @return {boolean}\n */\n get locked() {\n return this.getElementLocked(this.element);\n }\n\n /**\n * Lock/unlock an element.\n *\n * @param {Element} target the event target\n * @param {boolean} locked the new locked value\n */\n setElementLocked(target, locked) {\n target.dataset.locked = locked ?? false;\n if (locked) {\n // Disable interactions.\n target.style.pointerEvents = 'none';\n target.style.userSelect = 'none';\n // Check if it is draggable.\n if (target.hasAttribute('draggable')) {\n target.setAttribute('draggable', false);\n }\n } else {\n // Enable interactions.\n target.style.pointerEvents = null;\n target.style.userSelect = null;\n // Check if it was draggable.\n if (target.hasAttribute('draggable')) {\n target.setAttribute('draggable', true);\n }\n }\n }\n\n /**\n * Get the current locked value from the element.\n *\n * @param {Element} target the event target\n * @return {boolean}\n */\n getElementLocked(target) {\n return target.dataset.locked ?? false;\n }\n}\n"],"file":"basecomponent.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/reactive/basecomponent.js"],"names":["descriptor","element","HTMLElement","Error","eventHandlers","Map","eventListeners","selectors","events","constructor","getEvents","create","addSelectors","reactive","dispatchEvent","CustomEvent","bubbles","detail","component","registerComponent","addEventListener","event","stopPropagation","registerChildComponent","query","dataId","dataSelector","selector","querySelector","querySelectorAll","newSelectors","Object","entries","selectorName","eventName","target","file","data","Promise","resolve","reject","Templates","renderForPromise","then","html","js","replaceNodeContents","catch","error","type","listener","bindListener","get","bind","set","push","removeEventListener","forEach","unregister","remove","unregisterComponent","removeAllEventListeners","destroy","parentNode","locked","dataset","style","pointerEvents","userSelect","hasAttribute","setAttribute","setElementLocked","getElementLocked"],"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\nimport Templates from 'core/templates';\n\n/**\n * Reactive UI component base class.\n *\n * Each UI reactive component should extend this class to interact with a reactive state.\n *\n * @module core/local/reactive/basecomponent\n * @class core/local/reactive/basecomponent\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default class {\n\n /**\n * The component descriptor data structure.\n *\n * This structure is used by any component and init method to define the way the component will interact\n * with the interface and whith reactive instance operates. The logic behind this object is to avoid\n * unnecessary dependancies between the final interface and the state logic.\n *\n * Any component interacts with a single main DOM element (description.element) but it can use internal\n * selector to select elements within this main element (descriptor.selectors). By default each component\n * will provide it's own default selectors, but those can be overridden by the \"descriptor.selectors\"\n * property in case the mustache wants to reuse the same component logic but with a different interface.\n *\n * @typedef {object} descriptor\n * @property {Reactive} reactive an optional reactive module to register in\n * @property {DOMElement} element all components needs an element to anchor events\n * @property {object} [selectors] an optional object to override query selectors\n */\n\n /**\n * The class constructor.\n *\n * The only param this method gets is a constructor with all the mandatory\n * and optional component data. Component will receive the same descriptor\n * as create method param.\n *\n * This method will call the \"create\" method before registering the component into\n * the reactive module. This way any component can add default selectors and events.\n *\n * @param {descriptor} descriptor data to create the object.\n */\n constructor(descriptor) {\n\n if (descriptor.element === undefined || !(descriptor.element instanceof HTMLElement)) {\n throw Error(`Reactive components needs a main DOM element to dispatch events`);\n }\n\n this.element = descriptor.element;\n\n // Variable to track event listeners.\n this.eventHandlers = new Map([]);\n this.eventListeners = [];\n\n // Empty default component selectors.\n this.selectors = {};\n\n // Empty default event list from the static method.\n this.events = this.constructor.getEvents();\n\n // Call create function to get the component defaults.\n this.create(descriptor);\n\n // Overwrite the components selectors if necessary.\n if (descriptor.selectors !== undefined) {\n this.addSelectors(descriptor.selectors);\n }\n\n // Register into a reactive instance.\n if (descriptor.reactive === undefined) {\n // Ask parent components for registration.\n this.element.dispatchEvent(new CustomEvent(\n 'core/reactive:requestRegistration',\n {\n bubbles: true,\n detail: {component: this},\n }\n ));\n } else {\n this.reactive = descriptor.reactive;\n this.reactive.registerComponent(this);\n // Add a listener to register child components.\n this.addEventListener(\n this.element,\n 'core/reactive:requestRegistration',\n (event) => {\n if (event?.detail?.component) {\n event.stopPropagation();\n this.registerChildComponent(event.detail.component);\n }\n }\n );\n }\n }\n\n /**\n * Return the component custom event names.\n *\n * Components may override this method to provide their own events.\n *\n * Component custom events is an important part of component reusability. This function\n * is static because is part of the component definition and should be accessible from\n * outsite the instances. However, values will be available at instance level in the\n * this.events object.\n *\n * @returns {Object} the component events.\n */\n static getEvents() {\n return {};\n }\n\n /**\n * Component create function.\n *\n * Default init method will call \"create\" when all internal attributes are set\n * but before the component is not yet registered in the reactive module.\n *\n * In this method any component can define its own defaults such as:\n * - this.selectors {object} the default query selectors of this component.\n * - this.events {object} a list of event names this component dispatch\n * - extract any data from the main dom element (this.element)\n * - set any other data the component uses\n *\n * @param {descriptor} descriptor the component descriptor\n */\n // eslint-disable-next-line no-unused-vars\n create(descriptor) {\n // Components may override this method to initialize selects, events or other data.\n }\n\n /**\n * Component destroy hook.\n *\n * BaseComponent call this method when a component is unregistered or removed.\n *\n * Components may override this method to clean the HTML or do some action when the\n * component is unregistered or removed.\n */\n destroy() {\n // Components can override this method.\n }\n\n /**\n * Return the list of watchers that component has.\n *\n * Each watcher is represented by an object with two attributes:\n * - watch (string) the specific state event to watch. Example 'section.visible:updated'\n * - handler (function) the function to call when the watching state change happens\n *\n * Any component shoudl override this method to define their state watchers.\n *\n * @returns {array} array of watchers.\n */\n getWatchers() {\n return [];\n }\n\n /**\n * Reactive module will call this method when the state is ready.\n *\n * Component can override this method to update/load the component HTML or to bind\n * listeners to HTML entities.\n */\n stateReady() {\n // Components can override this method.\n }\n\n /**\n * Get the main DOM element of this component or a subelement.\n *\n * @param {string|undefined} query optional subelement query\n * @param {string|undefined} dataId optional data-id value\n * @returns {element|undefined} the DOM element (if any)\n */\n getElement(query, dataId) {\n if (query === undefined && dataId === undefined) {\n return this.element;\n }\n const dataSelector = (dataId) ? `[data-id='${dataId}']` : '';\n const selector = `${query ?? ''}${dataSelector}`;\n return this.element.querySelector(selector);\n }\n\n /**\n * Get the all subelement that match a query selector.\n *\n * @param {string|undefined} query optional subelement query\n * @param {string|undefined} dataId optional data-id value\n * @returns {NodeList} the DOM elements\n */\n getElements(query, dataId) {\n const dataSelector = (dataId) ? `[data-id='${dataId}']` : '';\n const selector = `${query ?? ''}${dataSelector}`;\n return this.element.querySelectorAll(selector);\n }\n\n /**\n * Add or update the component selectors.\n *\n * @param {Object} newSelectors an object of new selectors.\n */\n addSelectors(newSelectors) {\n for (const [selectorName, selector] of Object.entries(newSelectors)) {\n this.selectors[selectorName] = selector;\n }\n }\n\n /**\n * Return a component selector.\n *\n * @param {string} selectorName the selector name\n * @return {string|undefined} the query selector\n */\n getSelector(selectorName) {\n return this.selectors[selectorName];\n }\n\n /**\n * Dispatch a custom event on this.element.\n *\n * This is just a convenient method to dispatch custom events from within a component.\n * Components are free to use an alternative function to dispatch custom\n * events. The only restriction is that it should be dispatched on this.element\n * and specify \"bubbles:true\" to alert any component listeners.\n *\n * @param {string} eventName the event name\n * @param {*} detail event detail data\n */\n dispatchEvent(eventName, detail) {\n this.element.dispatchEvent(new CustomEvent(eventName, {\n bubbles: true,\n detail: detail,\n }));\n }\n\n /**\n * Render a new Component using a mustache file.\n *\n * It is important to note that this method should NOT be used for loading regular mustache files\n * as it returns a Promise that will only be resolved if the mustache registers a component instance.\n *\n * @param {element} target the DOM element that contains the component\n * @param {string} file the component mustache file to render\n * @param {*} data the mustache data\n * @return {Promise} a promise of the resulting component instance\n */\n renderComponent(target, file, data) {\n return new Promise((resolve, reject) => {\n target.addEventListener('ComponentRegistration:Success', ({detail}) => {\n resolve(detail.component);\n });\n target.addEventListener('ComponentRegistration:Fail', () => {\n reject(`Registration of ${file} fails.`);\n });\n Templates.renderForPromise(\n file,\n data\n ).then(({html, js}) => {\n Templates.replaceNodeContents(target, html, js);\n return true;\n }).catch(error => {\n reject(`Rendering of ${file} throws an error.`);\n throw error;\n });\n });\n }\n\n /**\n * Add and bind an event listener to a target and keep track of all event listeners.\n *\n * The native element.addEventListener method is not object oriented friently as the\n * \"this\" represents the element that triggers the event and not the listener class.\n * As components can be unregister and removed at any time, the BaseComponent provides\n * this method to keep track of all component listeners and do all of the bind stuff.\n *\n * @param {Element} target the event target\n * @param {string} type the event name\n * @param {function} listener the class method that recieve the event\n */\n addEventListener(target, type, listener) {\n\n // Check if we have the bind version of that listener.\n let bindListener = this.eventHandlers.get(listener);\n\n if (bindListener === undefined) {\n bindListener = listener.bind(this);\n this.eventHandlers.set(listener, bindListener);\n }\n\n target.addEventListener(type, bindListener);\n\n // Keep track of all component event listeners in case we need to remove them.\n this.eventListeners.push({\n target,\n type,\n bindListener,\n });\n\n }\n\n /**\n * Remove an event listener from a component.\n *\n * This method allows components to remove listeners without keeping track of the\n * listeners bind versions of the method. Both addEventListener and removeEventListener\n * keeps internally the relation between the original class method and the bind one.\n *\n * @param {Element} target the event target\n * @param {string} type the event name\n * @param {function} listener the class method that recieve the event\n */\n removeEventListener(target, type, listener) {\n // Check if we have the bind version of that listener.\n let bindListener = this.eventHandlers.get(listener);\n\n if (bindListener === undefined) {\n // This listener has not been added.\n return;\n }\n\n target.removeEventListener(type, bindListener);\n }\n\n /**\n * Remove all event listeners from this component.\n *\n * This method is called also when the component is unregistered or removed.\n *\n * Note that only listeners registered with the addEventListener method\n * will be removed. Other manual listeners will keep active.\n */\n removeAllEventListeners() {\n this.eventListeners.forEach(({target, type, bindListener}) => {\n target.removeEventListener(type, bindListener);\n });\n this.eventListeners = [];\n }\n\n /**\n * Remove a previously rendered component instance.\n *\n * This method will remove the component HTML and unregister it from the\n * reactive module.\n */\n remove() {\n this.unregister();\n this.element.remove();\n }\n\n /**\n * Unregister the component from the reactive module.\n *\n * This method will disable the component logic, event listeners and watchers\n * but it won't remove any HTML created by the component. However, it will trigger\n * the destroy hook to allow the component to clean parts of the interface.\n */\n unregister() {\n this.reactive.unregisterComponent(this);\n this.removeAllEventListeners();\n this.destroy();\n }\n\n /**\n * Dispatch a component registration event to inform the parent node.\n *\n * The registration event is different from the rest of the component events because\n * is the only way in which components can communicate its existence to a possible parent.\n * Most components will be created by including a mustache file, child components\n * must emit a registration event to the parent DOM element to alert about the registration.\n */\n dispatchRegistrationSuccess() {\n // The registration event does not bubble because we just want to comunicate with the parentNode.\n // Otherwise, any component can get multiple registrations events and could not differentiate\n // between child components and grand child components.\n if (this.element.parentNode === undefined) {\n return;\n }\n // This custom element is captured by renderComponent method.\n this.element.parentNode.dispatchEvent(new CustomEvent(\n 'ComponentRegistration:Success',\n {\n bubbles: false,\n detail: {component: this},\n }\n ));\n }\n\n /**\n * Dispatch a component registration fail event to inform the parent node.\n *\n * As dispatchRegistrationSuccess, this method will communicate the registration fail to the\n * parent node to inform the possible parent component.\n */\n dispatchRegistrationFail() {\n if (this.element.parentNode === undefined) {\n return;\n }\n // This custom element is captured only by renderComponent method.\n this.element.parentNode.dispatchEvent(new CustomEvent(\n 'ComponentRegistration:Fail',\n {\n bubbles: false,\n detail: {component: this},\n }\n ));\n }\n\n /**\n * Register a child component into the reactive instance.\n *\n * @param {self} component the component to register.\n */\n registerChildComponent(component) {\n component.reactive = this.reactive;\n this.reactive.registerComponent(component);\n }\n\n /**\n * Set the lock value and locks or unlocks the element.\n *\n * @param {boolean} locked the new locked value\n */\n set locked(locked) {\n this.setElementLocked(this.element, locked);\n }\n\n /**\n * Get the current locked value from the element.\n *\n * @return {boolean}\n */\n get locked() {\n return this.getElementLocked(this.element);\n }\n\n /**\n * Lock/unlock an element.\n *\n * @param {Element} target the event target\n * @param {boolean} locked the new locked value\n */\n setElementLocked(target, locked) {\n target.dataset.locked = locked ?? false;\n if (locked) {\n // Disable interactions.\n target.style.pointerEvents = 'none';\n target.style.userSelect = 'none';\n // Check if it is draggable.\n if (target.hasAttribute('draggable')) {\n target.setAttribute('draggable', false);\n }\n target.setAttribute('aria-busy', true);\n } else {\n // Enable interactions.\n target.style.pointerEvents = null;\n target.style.userSelect = null;\n // Check if it was draggable.\n if (target.hasAttribute('draggable')) {\n target.setAttribute('draggable', true);\n }\n target.setAttribute('aria-busy', false);\n }\n }\n\n /**\n * Get the current locked value from the element.\n *\n * @param {Element} target the event target\n * @return {boolean}\n */\n getElementLocked(target) {\n return target.dataset.locked ?? false;\n }\n}\n"],"file":"basecomponent.min.js"} \ No newline at end of file diff --git a/lib/amd/src/local/reactive/basecomponent.js b/lib/amd/src/local/reactive/basecomponent.js index 3b28e3b6d00..f276df1c5be 100644 --- a/lib/amd/src/local/reactive/basecomponent.js +++ b/lib/amd/src/local/reactive/basecomponent.js @@ -466,6 +466,7 @@ export default class { if (target.hasAttribute('draggable')) { target.setAttribute('draggable', false); } + target.setAttribute('aria-busy', true); } else { // Enable interactions. target.style.pointerEvents = null; @@ -474,6 +475,7 @@ export default class { if (target.hasAttribute('draggable')) { target.setAttribute('draggable', true); } + target.setAttribute('aria-busy', false); } } diff --git a/theme/boost/scss/moodle/course.scss b/theme/boost/scss/moodle/course.scss index f1b8f910537..833d2b77df4 100644 --- a/theme/boost/scss/moodle/course.scss +++ b/theme/boost/scss/moodle/course.scss @@ -1,7 +1,5 @@ /* course.less */ -$course-editinprogress-bg: $gray-100 !default; - /* COURSE CONTENT */ .section_add_menus { @@ -189,24 +187,59 @@ body:not(.editing) .sitetopic ul.section { } } } + // Remove old spinners if the reactive state is ready. + .course-content .stateready .section .spinner { + display: none; + } + // New editing in progress spinners. .editinprogress { - opacity: .7; - animation: editinprogress-pulse 2s infinite linear; + position: relative; + + & > * { + opacity: .4; + } + + .corelightbox, + .lightbox { + display: none; + } + + &:after { + position: absolute; + font-family: "FontAwesome"; + font-size: 20px; + color: $gray-600; + content: ""; + display: flex; + justify-content: center; + align-items: center; + width: 30px; + height: 30px; + left: calc(50% - 15px); + top: calc(50% - 15px); + animation: editinprogress-rotation 2s infinite linear; + } + + // Prevent inner editingprogress. + .editinprogress { + &:after { + display: none; + } + } } } -@keyframes editinprogress-pulse { +@keyframes editinprogress-rotation { 0% { - background-color: $course-editinprogress-bg; - filter: grayscale(60%); + opacity: 0; + transform: rotate(0deg); } 50% { - background-color: darken($course-editinprogress-bg, 5%); - filter: grayscale(40%); + opacity: 1; } 100% { - background-color: $course-editinprogress-bg; - filter: grayscale(60%); + opacity: 0; + transform: rotate(359deg); } } diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index dc74d32b7f6..5bc0548366d 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -13774,20 +13774,42 @@ body:not(.editing) .sitetopic ul.section { */ padding-left: 2rem; } -.editing .editinprogress { - opacity: .7; - animation: editinprogress-pulse 2s infinite linear; } +.editing .course-content .stateready .section .spinner { + display: none; } -@keyframes editinprogress-pulse { +.editing .editinprogress { + position: relative; } + .editing .editinprogress > * { + opacity: .4; } + .editing .editinprogress .corelightbox, + .editing .editinprogress .lightbox { + display: none; } + .editing .editinprogress:after { + position: absolute; + font-family: "FontAwesome"; + font-size: 20px; + color: #6a737b; + content: ""; + display: flex; + justify-content: center; + align-items: center; + width: 30px; + height: 30px; + left: calc(50% - 15px); + top: calc(50% - 15px); + animation: editinprogress-rotation 2s infinite linear; } + .editing .editinprogress .editinprogress:after { + display: none; } + +@keyframes editinprogress-rotation { 0% { - background-color: #f8f9fa; - filter: grayscale(60%); } + opacity: 0; + transform: rotate(0deg); } 50% { - background-color: #e9ecef; - filter: grayscale(40%); } + opacity: 1; } 100% { - background-color: #f8f9fa; - filter: grayscale(60%); } } + opacity: 0; + transform: rotate(359deg); } } .editing_show + .editing_assign, .editing_hide + .editing_assign { diff --git a/theme/classic/style/moodle.css b/theme/classic/style/moodle.css index 11474d12222..929e3196fe6 100644 --- a/theme/classic/style/moodle.css +++ b/theme/classic/style/moodle.css @@ -13774,20 +13774,42 @@ body:not(.editing) .sitetopic ul.section { */ padding-left: 2rem; } -.editing .editinprogress { - opacity: .7; - animation: editinprogress-pulse 2s infinite linear; } +.editing .course-content .stateready .section .spinner { + display: none; } -@keyframes editinprogress-pulse { +.editing .editinprogress { + position: relative; } + .editing .editinprogress > * { + opacity: .4; } + .editing .editinprogress .corelightbox, + .editing .editinprogress .lightbox { + display: none; } + .editing .editinprogress:after { + position: absolute; + font-family: "FontAwesome"; + font-size: 20px; + color: #6a737b; + content: ""; + display: flex; + justify-content: center; + align-items: center; + width: 30px; + height: 30px; + left: calc(50% - 15px); + top: calc(50% - 15px); + animation: editinprogress-rotation 2s infinite linear; } + .editing .editinprogress .editinprogress:after { + display: none; } + +@keyframes editinprogress-rotation { 0% { - background-color: #f8f9fa; - filter: grayscale(60%); } + opacity: 0; + transform: rotate(0deg); } 50% { - background-color: #e9ecef; - filter: grayscale(40%); } + opacity: 1; } 100% { - background-color: #f8f9fa; - filter: grayscale(60%); } } + opacity: 0; + transform: rotate(359deg); } } .editing_show + .editing_assign, .editing_hide + .editing_assign {