diff --git a/public/course/format/amd/build/local/content/actions.min.js b/public/course/format/amd/build/local/content/actions.min.js index 344b3607e0c..75dcba95285 100644 --- a/public/course/format/amd/build/local/content/actions.min.js +++ b/public/course/format/amd/build/local/content/actions.min.js @@ -9,6 +9,6 @@ define("core_courseformat/local/content/actions",["exports","core/reactive","cor * @class core_courseformat/local/content/actions * @copyright 2021 Ferran Recio * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_collapse=_interopRequireDefault(_collapse),_log=_interopRequireDefault(_log),_modal=_interopRequireDefault(_modal),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_modal_delete_cancel=_interopRequireDefault(_modal_delete_cancel),_modal_copy_to_clipboard=_interopRequireDefault(_modal_copy_to_clipboard),_modal_events=_interopRequireDefault(_modal_events),_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending),_contenttree=_interopRequireDefault(_contenttree),(0,_prefetch.prefetchStrings)("core",["movecoursesection","movecoursemodule","confirm","delete"]);const directMutations={sectionHide:"sectionHide",sectionShow:"sectionShow",cmHide:"cmHide",cmShow:"cmShow",cmStealth:"cmStealth",cmMoveRight:"cmMoveRight",cmMoveLeft:"cmMoveLeft",cmNoGroups:"cmNoGroups",cmSeparateGroups:"cmSeparateGroups",cmVisibleGroups:"cmVisibleGroups"};class _default extends _reactive.BaseComponent{create(){this.name="content_actions",this.selectors={ACTIONLINK:"[data-action]",SECTIONLINK:"[data-for='section']",CMLINK:"[data-for='cm']",SECTIONNODE:"[data-for='sectionnode']",MODALTOGGLER:"[data-bs-toggle='collapse']",ADDSECTION:"[data-action='addSection']",CONTENTTREE:"#destination-selector",ACTIONMENU:".action-menu",ACTIONMENUTOGGLER:'[data-bs-toggle="dropdown"]',OPTIONSRADIO:"[type='radio']",COURSEADDSECTION:"#course-addsection",ADDSECTIONREGION:"[data-region='section-addsection']"},this.classes={DISABLED:"disabled",ITALIC:"fst-italic",DISPLAYNONE:"d-none"}}static addActions(actions){for(const[action,mutationReference]of Object.entries(actions)){if("function"!=typeof mutationReference&&"string"!=typeof mutationReference)throw new Error("".concat(action," action must be a mutation name or a function"));directMutations[action]=mutationReference}}stateReady(){this.addEventListener(this.element,"click",this._dispatchClick),this.addEventListener(this.element,_events.eventTypes.elementUpdated,this._inplaceEditableHandler)}_dispatchClick(event){const target=event.target.closest(this.selectors.ACTIONLINK);if(!target)return;if(target.classList.contains(this.classes.DISABLED))return void event.preventDefault();const actionName=target.dataset.action,methodName=this._actionMethodName(actionName);if(void 0===this[methodName])return void 0!==directMutations[actionName]?"function"==typeof directMutations[actionName]?void directMutations[actionName](target,event):void this._requestMutationAction(target,event,directMutations[actionName]):void 0;this[methodName](target,event)}_actionMethodName(name){const requestName=name.charAt(0).toUpperCase()+name.slice(1);return"_request".concat(requestName)}_inplaceEditableHandler(event){var _event$detail,_event$detail$ajaxret,_event$detail2,_event$detail2$ajaxre;const itemtype=null===(_event$detail=event.detail)||void 0===_event$detail||null===(_event$detail$ajaxret=_event$detail.ajaxreturn)||void 0===_event$detail$ajaxret?void 0:_event$detail$ajaxret.itemtype,itemid=parseInt(null===(_event$detail2=event.detail)||void 0===_event$detail2||null===(_event$detail2$ajaxre=_event$detail2.ajaxreturn)||void 0===_event$detail2$ajaxre?void 0:_event$detail2$ajaxre.itemid);Number.isFinite(itemid)&&itemtype&&("activityname"!==itemtype?"sectionname"!==itemtype&&"sectionnamenl"!==itemtype||this.reactive.dispatch("sectionState",[itemid]):this.reactive.dispatch("cmState",[itemid]))}_getTargetIds(target){var _target$dataset,_target$dataset2;let ids=[];null!=target&&null!==(_target$dataset=target.dataset)&&void 0!==_target$dataset&&_target$dataset.id&&ids.push(target.dataset.id);const bulkType=null==target||null===(_target$dataset2=target.dataset)||void 0===_target$dataset2?void 0:_target$dataset2.bulk;if(!bulkType)return ids;const bulk=this.reactive.get("bulk");return bulk.enabled&&bulk.selectedType===bulkType&&(ids=[...ids,...bulk.selection]),ids}async _requestMoveSection(target,event){const sectionIds=this._getTargetIds(target);if(0==sectionIds.length)return;event.preventDefault();const pendingModalReady=new _pending.default("courseformat/actions:prepareMoveSectionModal"),editTools=this._getClosestActionMenuToogler(target),data=this.reactive.getExporter().course(this.reactive.state);let titleText=null,sectionInfo=null;1==sectionIds.length?(sectionInfo=this.reactive.get("section",sectionIds[0]),data.sectionid=sectionInfo.id,data.sectiontitle=sectionInfo.title,data.information=await this.reactive.getFormatString("sectionmove_info",data.sectiontitle),titleText=this.reactive.getFormatString("sectionmove_title")):(data.information=await this.reactive.getFormatString("sectionsmove_info",sectionIds.length),titleText=this.reactive.getFormatString("sectionsmove_title"));const modal=await this._modalBodyRenderedPromise(_modal.default,{title:titleText,body:_templates.default.render("core_courseformat/local/content/movesection",data)}),modalBody=(0,_normalise.getFirst)(modal.getBody());sectionIds.forEach((sectionId=>{const currentElement=modalBody.querySelector("".concat(this.selectors.SECTIONLINK,"[data-id='").concat(sectionId,"']"));this._disableLink(currentElement)})),new _contenttree.default(modalBody.querySelector(this.selectors.CONTENTTREE),{SECTION:this.selectors.SECTIONNODE,TOGGLER:this.selectors.MODALTOGGLER,COLLAPSE:this.selectors.MODALTOGGLER},!0),modalBody.addEventListener("click",(event=>{const target=event.target;target.matches("a")&&"section"==target.dataset.for&&void 0!==target.dataset.id&&(target.getAttribute("aria-disabled")||(event.preventDefault(),this.reactive.dispatch("sectionMoveAfter",sectionIds,target.dataset.id),this._destroyModal(modal,editTools)))})),pendingModalReady.resolve()}async _requestMoveCm(target,event){const cmIds=this._getTargetIds(target);if(0==cmIds.length)return;event.preventDefault();const pendingModalReady=new _pending.default("courseformat/actions:prepareMoveCmModal"),editTools=this._getClosestActionMenuToogler(target),exporter=this.reactive.getExporter(),data=exporter.course(this.reactive.state);let titleText=null;if(1==cmIds.length){const cmInfo=this.reactive.get("cm",cmIds[0]);data.cmid=cmInfo.id,data.cmname=cmInfo.name,data.information=await this.reactive.getFormatString("cmmove_info",data.cmname),titleText=cmInfo.hasdelegatedsection?this.reactive.getFormatString("cmmove_subsectiontitle"):this.reactive.getFormatString("cmmove_title")}else data.information=await this.reactive.getFormatString("cmsmove_info",cmIds.length),titleText=this.reactive.getFormatString("cmsmove_title");const modal=await this._modalBodyRenderedPromise(_modal.default,{title:titleText,body:_templates.default.render("core_courseformat/local/content/movecm",data)}),modalBody=(0,_normalise.getFirst)(modal.getBody());cmIds.forEach((cmId=>{const currentElement=modalBody.querySelector("".concat(this.selectors.CMLINK,"[data-id='").concat(cmId,"']"));this._disableLink(currentElement)})),new _contenttree.default(modalBody.querySelector(this.selectors.CONTENTTREE),{SECTION:this.selectors.SECTIONNODE,TOGGLER:this.selectors.MODALTOGGLER,COLLAPSE:this.selectors.MODALTOGGLER,ENTER:this.selectors.SECTIONLINK}),cmIds.forEach((cmId=>{const cmInfo=this.reactive.get("cm",cmId);let selector;selector=cmInfo.hasdelegatedsection?"".concat(this.selectors.SECTIONLINK,"[data-id='").concat(cmInfo.sectionid,"']"):"".concat(this.selectors.CMLINK,"[data-id='").concat(cmId,"']");const currentElement=modalBody.querySelector(selector);this._expandCmMoveModalParentSections(modalBody,currentElement)})),modalBody.addEventListener("click",(event=>{const target=event.target;if(!target.matches("a")||void 0===target.dataset.for||void 0===target.dataset.id)return;if(target.getAttribute("aria-disabled"))return;let targetSectionId,targetCmId;event.preventDefault();let droppedCmIds=[...cmIds];if("cm"==target.dataset.for){const dropData=exporter.cmDraggableData(this.reactive.state,target.dataset.id);targetSectionId=dropData.sectionid,targetCmId=dropData.nextcmid}else{const section=this.reactive.get("section",target.dataset.id);targetSectionId=target.dataset.id,targetCmId=null==section?void 0:section.cmlist[0]}this.reactive.get("section",targetSectionId).component&&(droppedCmIds=droppedCmIds.filter((cmId=>!this.reactive.get("cm",cmId).hasdelegatedsection))),0!==droppedCmIds.length&&(this.reactive.dispatch("cmMove",droppedCmIds,targetSectionId,targetCmId),this._destroyModal(modal,editTools))})),pendingModalReady.resolve()}_expandCmMoveModalParentSections(modalBody,element){var _toggler$dataset$targ;const sectionnode=element.closest(this.selectors.SECTIONNODE);if(!sectionnode)return;const toggler=sectionnode.querySelector(this.selectors.MODALTOGGLER);let collapsibleId=null!==(_toggler$dataset$targ=toggler.dataset.target)&&void 0!==_toggler$dataset$targ?_toggler$dataset$targ:toggler.getAttribute("href");if(collapsibleId){collapsibleId=collapsibleId.replace("#","");const expandNode=modalBody.querySelector("#".concat(collapsibleId));new _collapse.default(expandNode,{toggle:!1}).show()}this._expandCmMoveModalParentSections(modalBody,sectionnode.parentElement)}async _requestAddSection(target,event){var _target$dataset$id;event.preventDefault(),this.reactive.dispatch("addSection",null!==(_target$dataset$id=target.dataset.id)&&void 0!==_target$dataset$id?_target$dataset$id:0)}async _requestAddModule(target,event){_log.default.debug("AddModule action is deprecated. Use newModule instead"),event.preventDefault(),this.reactive.dispatch("addModule",target.dataset.modname,target.dataset.sectionnum,target.dataset.beforemod)}async _requestNewModule(target,event){event.preventDefault(),this.reactive.dispatch("newModule",target.dataset.modname,target.dataset.sectionid,target.dataset.beforemod)}async _requestDeleteSection(target,event){const sectionIds=this._getTargetIds(target);if(0==sectionIds.length)return;if(event.preventDefault(),!sectionIds.some((sectionId=>{var _sectionInfo$cmlist;const sectionInfo=this.reactive.get("section",sectionId);return(null!==(_sectionInfo$cmlist=sectionInfo.cmlist)&&void 0!==_sectionInfo$cmlist?_sectionInfo$cmlist:[]).length||sectionInfo.hassummary||sectionInfo.rawtitle})))return void this._dispatchSectionDelete(sectionIds,target);let bodyText=null,titleText=null;if(1==sectionIds.length){titleText=this.reactive.getFormatString("sectiondelete_title");const sectionInfo=this.reactive.get("section",sectionIds[0]);bodyText=this.reactive.getFormatString("sectiondelete_info",{name:sectionInfo.title})}else titleText=this.reactive.getFormatString("sectionsdelete_title"),bodyText=this.reactive.getFormatString("sectionsdelete_info",{count:sectionIds.length});const modal=await this._modalBodyRenderedPromise(_modal_delete_cancel.default,{title:titleText,body:bodyText});modal.getRoot().on(_modal_events.default.delete,(e=>{e.preventDefault(),modal.destroy(),this._dispatchSectionDelete(sectionIds,target)}))}async _dispatchSectionDelete(sectionIds,target){await this.reactive.dispatch("sectionDelete",sectionIds),target.baseURI.includes("section.php")&&(window.location.href=this.reactive.get("course").baseurl)}async _requestToggleSelectionCm(target,event){(0,_bulkselection.toggleBulkSelectionAction)(this.reactive,target,event,"cm")}async _requestToggleSelectionSection(target,event){(0,_bulkselection.toggleBulkSelectionAction)(this.reactive,target,event,"section")}async _requestMutationAction(target,event,mutationName){(target.dataset.id||"bulkaction"===target.dataset.for)&&(event.preventDefault(),"bulkaction"===target.dataset.for?this.reactive.dispatch(mutationName,this.reactive.get("bulk").selection):this.reactive.dispatch(mutationName,[target.dataset.id]))}_requestPermalink(target,event){event.preventDefault(),_modal_copy_to_clipboard.default.create({text:target.getAttribute("href")},(0,_str.getString)("sectionlink","course"))}async _requestCmDuplicate(target,event){var _target$dataset$secti;const cmIds=this._getTargetIds(target);if(0==cmIds.length)return;const sectionId=null!==(_target$dataset$secti=target.dataset.sectionid)&&void 0!==_target$dataset$secti?_target$dataset$secti:null;event.preventDefault(),this.reactive.dispatch("cmDuplicate",cmIds,sectionId)}async _requestCmDelete(target,event){const cmIds=this._getTargetIds(target);if(0==cmIds.length)return;event.preventDefault();let bodyText=null,titleText=null,delegatedsection=null;if(1==cmIds.length){const cmInfo=this.reactive.get("cm",cmIds[0]);cmInfo.hasdelegatedsection?(delegatedsection=cmInfo.delegatesectionid,titleText=this.reactive.getFormatString("cmdelete_subsectiontitle"),bodyText=(0,_str.getString)("sectiondelete_info","core_courseformat",{type:cmInfo.modname,name:cmInfo.name})):(titleText=this.reactive.getFormatString("cmdelete_title"),bodyText=(0,_str.getString)("cmdelete_info","core_courseformat",{type:cmInfo.modname,name:cmInfo.name}))}else titleText=(0,_str.getString)("cmsdelete_title","core_courseformat"),bodyText=(0,_str.getString)("cmsdelete_info","core_courseformat",{count:cmIds.length});const modal=await this._modalBodyRenderedPromise(_modal_delete_cancel.default,{title:titleText,body:bodyText});modal.getRoot().on(_modal_events.default.delete,(e=>{if(e.preventDefault(),modal.destroy(),this.reactive.dispatch("cmDelete",cmIds),1==cmIds.length&&delegatedsection&&target.baseURI.includes("section.php")){let parameters=new URLSearchParams(window.location.search);parameters.has("id")&¶meters.get("id")==delegatedsection&&this._dispatchSectionDelete([delegatedsection],target)}}))}async _requestCmAvailability(target){const cmIds=this._getTargetIds(target);if(0==cmIds.length)return;const data={allowstealth:this.reactive.getExporter().canUseStealth(this.reactive.state,cmIds)},modal=await this._modalBodyRenderedPromise(_modal_save_cancel.default,{title:(0,_str.getString)("availability","core"),body:_templates.default.render("core_courseformat/local/content/cm/availabilitymodal",data),saveButtonText:(0,_str.getString)("apply","core")});this._setupMutationRadioButtonModal(modal,cmIds)}async _requestSectionAvailability(target){const sectionIds=this._getTargetIds(target);if(0==sectionIds.length)return;const title=1==sectionIds.length?"sectionavailability_title":"sectionsavailability_title",modal=await this._modalBodyRenderedPromise(_modal_save_cancel.default,{title:this.reactive.getFormatString(title),body:_templates.default.render("core_courseformat/local/content/section/availabilitymodal",[]),saveButtonText:(0,_str.getString)("apply","core")});this._setupMutationRadioButtonModal(modal,sectionIds)}_setupMutationRadioButtonModal(modal,ids){modal.setButtonDisabled("save",!0);const submitFunction=radio=>{const mutation=null==radio?void 0:radio.value;return!!mutation&&(this.reactive.dispatch(mutation,ids),!0)},modalBody=(0,_normalise.getFirst)(modal.getBody());modalBody.querySelectorAll(this.selectors.OPTIONSRADIO).forEach((radio=>{radio.addEventListener("change",(()=>{modal.setButtonDisabled("save",!1)})),radio.parentNode.addEventListener("click",(()=>{radio.checked=!0,modal.setButtonDisabled("save",!1)})),radio.parentNode.addEventListener("dblclick",(dbClickEvent=>{submitFunction(radio)&&(dbClickEvent.preventDefault(),modal.destroy())}))})),modal.getRoot().on(_modal_events.default.save,(()=>{const radio=modalBody.querySelector("".concat(this.selectors.OPTIONSRADIO,":checked"));submitFunction(radio)}))}_disableLink(element){element&&(element.style.pointerEvents="none",element.style.userSelect="none",element.classList.add(this.classes.DISABLED),element.classList.add(this.classes.ITALIC),element.setAttribute("aria-disabled",!0),element.addEventListener("click",(event=>event.preventDefault())))}_modalBodyRenderedPromise(ModalClass,modalParams){return new Promise(((resolve,reject)=>{ModalClass.create(modalParams).then((modal=>{modal.setRemoveOnClose(!0),modal.getRoot().on(_modal_events.default.bodyRendered,(()=>{resolve(modal)})),void 0!==modalParams.saveButtonText&&modal.setSaveButtonText(modalParams.saveButtonText),void 0!==modalParams.deleteButtonText&&modal.setDeleteButtonText(modalParams.saveButtonText),modal.show()})).catch((()=>{reject("Cannot load modal content")}))}))}_destroyModal(modal,element){modal.hide();const pendingDestroy=new _pending.default("courseformat/actions:destroyModal");element&&element.focus(),setTimeout((()=>{modal.destroy(),pendingDestroy.resolve()}),500)}_getClosestActionMenuToogler(element){const actionMenu=element.closest(this.selectors.ACTIONMENU);if(actionMenu)return actionMenu.querySelector(this.selectors.ACTIONMENUTOGGLER)}}return _exports.default=_default,_exports.default})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_collapse=_interopRequireDefault(_collapse),_log=_interopRequireDefault(_log),_modal=_interopRequireDefault(_modal),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_modal_delete_cancel=_interopRequireDefault(_modal_delete_cancel),_modal_copy_to_clipboard=_interopRequireDefault(_modal_copy_to_clipboard),_modal_events=_interopRequireDefault(_modal_events),_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending),_contenttree=_interopRequireDefault(_contenttree),(0,_prefetch.prefetchStrings)("core",["movecoursesection","movecoursemodule","confirm","delete"]);const directMutations={sectionHide:"sectionHide",sectionShow:"sectionShow",cmHide:"cmHide",cmShow:"cmShow",cmStealth:"cmStealth",cmMoveRight:"cmMoveRight",cmMoveLeft:"cmMoveLeft",cmNoGroups:"cmNoGroups",cmSeparateGroups:"cmSeparateGroups",cmVisibleGroups:"cmVisibleGroups"};class _default extends _reactive.BaseComponent{create(){this.name="content_actions",this.selectors={ACTIONLINK:"[data-action]",SECTIONLINK:"[data-for='section']",CMLINK:"[data-for='cm']",SECTIONNODE:"[data-for='sectionnode']",MODALTOGGLER:"[data-bs-toggle='collapse']",ADDSECTION:"[data-action='addSection']",CONTENTTREE:"#destination-selector",ACTIONMENU:".action-menu",ACTIONMENUTOGGLER:'[data-bs-toggle="dropdown"]',OPTIONSRADIO:"[type='radio']",COURSEADDSECTION:"#course-addsection",ADDSECTIONREGION:"[data-region='section-addsection']"},this.classes={DISABLED:"disabled",ITALIC:"fst-italic",DISPLAYNONE:"d-none"}}static addActions(actions){for(const[action,mutationReference]of Object.entries(actions)){if("function"!=typeof mutationReference&&"string"!=typeof mutationReference)throw new Error("".concat(action," action must be a mutation name or a function"));directMutations[action]=mutationReference}}stateReady(){this.addEventListener(this.element,"click",this._dispatchClick),this.addEventListener(this.element,_events.eventTypes.elementUpdated,this._inplaceEditableHandler)}_dispatchClick(event){const target=event.target.closest(this.selectors.ACTIONLINK);if(!target)return;if(target.classList.contains(this.classes.DISABLED))return void event.preventDefault();const actionName=target.dataset.action,methodName=this._actionMethodName(actionName);if(void 0===this[methodName])return void 0!==directMutations[actionName]?"function"==typeof directMutations[actionName]?void directMutations[actionName](target,event):void this._requestMutationAction(target,event,directMutations[actionName]):void 0;this[methodName](target,event)}_actionMethodName(name){const requestName=name.charAt(0).toUpperCase()+name.slice(1);return"_request".concat(requestName)}_inplaceEditableHandler(event){var _event$detail,_event$detail$ajaxret,_event$detail2,_event$detail2$ajaxre;const itemtype=null===(_event$detail=event.detail)||void 0===_event$detail||null===(_event$detail$ajaxret=_event$detail.ajaxreturn)||void 0===_event$detail$ajaxret?void 0:_event$detail$ajaxret.itemtype,itemid=parseInt(null===(_event$detail2=event.detail)||void 0===_event$detail2||null===(_event$detail2$ajaxre=_event$detail2.ajaxreturn)||void 0===_event$detail2$ajaxre?void 0:_event$detail2$ajaxre.itemid);Number.isFinite(itemid)&&itemtype&&("activityname"!==itemtype?"sectionname"!==itemtype&&"sectionnamenl"!==itemtype||this.reactive.dispatch("sectionState",[itemid]):this.reactive.dispatch("cmState",[itemid]))}_getTargetIds(target){var _target$dataset,_target$dataset2;let ids=[];null!=target&&null!==(_target$dataset=target.dataset)&&void 0!==_target$dataset&&_target$dataset.id&&ids.push(target.dataset.id);const bulkType=null==target||null===(_target$dataset2=target.dataset)||void 0===_target$dataset2?void 0:_target$dataset2.bulk;if(!bulkType)return ids;const bulk=this.reactive.get("bulk");return bulk.enabled&&bulk.selectedType===bulkType&&(ids=[...ids,...bulk.selection]),ids}async _requestMoveSection(target,event){const sectionIds=this._getTargetIds(target);if(0==sectionIds.length)return;event.preventDefault();const pendingModalReady=new _pending.default("courseformat/actions:prepareMoveSectionModal"),editTools=this._getClosestActionMenuToogler(target),data=this.reactive.getExporter().course(this.reactive.state);let titleText=null,sectionInfo=null;1==sectionIds.length?(sectionInfo=this.reactive.get("section",sectionIds[0]),data.sectionid=sectionInfo.id,data.sectiontitle=sectionInfo.title,data.information=await this.reactive.getFormatString("sectionmove_info",data.sectiontitle),titleText=this.reactive.getFormatString("sectionmove_title")):(data.information=await this.reactive.getFormatString("sectionsmove_info",sectionIds.length),titleText=this.reactive.getFormatString("sectionsmove_title"));const modal=await this._modalBodyRenderedPromise(_modal.default,{title:titleText,body:_templates.default.render("core_courseformat/local/content/movesection",data)}),modalBody=(0,_normalise.getFirst)(modal.getBody());sectionIds.forEach((sectionId=>{const currentElement=modalBody.querySelector("".concat(this.selectors.SECTIONLINK,"[data-id='").concat(sectionId,"']"));this._disableLink(currentElement)})),new _contenttree.default(modalBody.querySelector(this.selectors.CONTENTTREE),{SECTION:this.selectors.SECTIONNODE,TOGGLER:this.selectors.MODALTOGGLER,COLLAPSE:this.selectors.MODALTOGGLER},!0),modalBody.addEventListener("click",(event=>{const target=event.target.closest("a");target&&"section"==target.dataset.for&&void 0!==target.dataset.id&&(target.getAttribute("aria-disabled")||(event.preventDefault(),this.reactive.dispatch("sectionMoveAfter",sectionIds,target.dataset.id),this._destroyModal(modal,editTools)))})),pendingModalReady.resolve()}async _requestMoveCm(target,event){const cmIds=this._getTargetIds(target);if(0==cmIds.length)return;event.preventDefault();const pendingModalReady=new _pending.default("courseformat/actions:prepareMoveCmModal"),editTools=this._getClosestActionMenuToogler(target),exporter=this.reactive.getExporter(),data=exporter.course(this.reactive.state);let titleText=null;if(1==cmIds.length){const cmInfo=this.reactive.get("cm",cmIds[0]);data.cmid=cmInfo.id,data.cmname=cmInfo.name,data.information=await this.reactive.getFormatString("cmmove_info",data.cmname),titleText=cmInfo.hasdelegatedsection?this.reactive.getFormatString("cmmove_subsectiontitle"):this.reactive.getFormatString("cmmove_title")}else data.information=await this.reactive.getFormatString("cmsmove_info",cmIds.length),titleText=this.reactive.getFormatString("cmsmove_title");const modal=await this._modalBodyRenderedPromise(_modal.default,{title:titleText,body:_templates.default.render("core_courseformat/local/content/movecm",data)}),modalBody=(0,_normalise.getFirst)(modal.getBody());cmIds.forEach((cmId=>{const currentElement=modalBody.querySelector("".concat(this.selectors.CMLINK,"[data-id='").concat(cmId,"']"));this._disableLink(currentElement)})),new _contenttree.default(modalBody.querySelector(this.selectors.CONTENTTREE),{SECTION:this.selectors.SECTIONNODE,TOGGLER:this.selectors.MODALTOGGLER,COLLAPSE:this.selectors.MODALTOGGLER,ENTER:this.selectors.SECTIONLINK}),cmIds.forEach((cmId=>{const cmInfo=this.reactive.get("cm",cmId);let selector;selector=cmInfo.hasdelegatedsection?"".concat(this.selectors.SECTIONLINK,"[data-id='").concat(cmInfo.sectionid,"']"):"".concat(this.selectors.CMLINK,"[data-id='").concat(cmId,"']");const currentElement=modalBody.querySelector(selector);this._expandCmMoveModalParentSections(modalBody,currentElement)})),modalBody.addEventListener("click",(event=>{const target=event.target.closest("a");if(!target||void 0===target.dataset.for||void 0===target.dataset.id)return;if(target.getAttribute("aria-disabled"))return;let targetSectionId,targetCmId;event.preventDefault();let droppedCmIds=[...cmIds];if("cm"==target.dataset.for){const dropData=exporter.cmDraggableData(this.reactive.state,target.dataset.id);targetSectionId=dropData.sectionid,targetCmId=dropData.nextcmid}else{const section=this.reactive.get("section",target.dataset.id);targetSectionId=target.dataset.id,targetCmId=null==section?void 0:section.cmlist[0]}this.reactive.get("section",targetSectionId).component&&(droppedCmIds=droppedCmIds.filter((cmId=>!this.reactive.get("cm",cmId).hasdelegatedsection))),0!==droppedCmIds.length&&(this.reactive.dispatch("cmMove",droppedCmIds,targetSectionId,targetCmId),this._destroyModal(modal,editTools))})),pendingModalReady.resolve()}_expandCmMoveModalParentSections(modalBody,element){var _toggler$dataset$targ;const sectionnode=element.closest(this.selectors.SECTIONNODE);if(!sectionnode)return;const toggler=sectionnode.querySelector(this.selectors.MODALTOGGLER);let collapsibleId=null!==(_toggler$dataset$targ=toggler.dataset.target)&&void 0!==_toggler$dataset$targ?_toggler$dataset$targ:toggler.getAttribute("href");if(collapsibleId){collapsibleId=collapsibleId.replace("#","");const expandNode=modalBody.querySelector("#".concat(collapsibleId));new _collapse.default(expandNode,{toggle:!1}).show()}this._expandCmMoveModalParentSections(modalBody,sectionnode.parentElement)}async _requestAddSection(target,event){var _target$dataset$id;event.preventDefault(),this.reactive.dispatch("addSection",null!==(_target$dataset$id=target.dataset.id)&&void 0!==_target$dataset$id?_target$dataset$id:0)}async _requestAddModule(target,event){_log.default.debug("AddModule action is deprecated. Use newModule instead"),event.preventDefault(),this.reactive.dispatch("addModule",target.dataset.modname,target.dataset.sectionnum,target.dataset.beforemod)}async _requestNewModule(target,event){event.preventDefault(),this.reactive.dispatch("newModule",target.dataset.modname,target.dataset.sectionid,target.dataset.beforemod)}async _requestDeleteSection(target,event){const sectionIds=this._getTargetIds(target);if(0==sectionIds.length)return;if(event.preventDefault(),!sectionIds.some((sectionId=>{var _sectionInfo$cmlist;const sectionInfo=this.reactive.get("section",sectionId);return(null!==(_sectionInfo$cmlist=sectionInfo.cmlist)&&void 0!==_sectionInfo$cmlist?_sectionInfo$cmlist:[]).length||sectionInfo.hassummary||sectionInfo.rawtitle})))return void this._dispatchSectionDelete(sectionIds,target);let bodyText=null,titleText=null;if(1==sectionIds.length){titleText=this.reactive.getFormatString("sectiondelete_title");const sectionInfo=this.reactive.get("section",sectionIds[0]);bodyText=this.reactive.getFormatString("sectiondelete_info",{name:sectionInfo.title})}else titleText=this.reactive.getFormatString("sectionsdelete_title"),bodyText=this.reactive.getFormatString("sectionsdelete_info",{count:sectionIds.length});const modal=await this._modalBodyRenderedPromise(_modal_delete_cancel.default,{title:titleText,body:bodyText});modal.getRoot().on(_modal_events.default.delete,(e=>{e.preventDefault(),modal.destroy(),this._dispatchSectionDelete(sectionIds,target)}))}async _dispatchSectionDelete(sectionIds,target){await this.reactive.dispatch("sectionDelete",sectionIds),target.baseURI.includes("section.php")&&(window.location.href=this.reactive.get("course").baseurl)}async _requestToggleSelectionCm(target,event){(0,_bulkselection.toggleBulkSelectionAction)(this.reactive,target,event,"cm")}async _requestToggleSelectionSection(target,event){(0,_bulkselection.toggleBulkSelectionAction)(this.reactive,target,event,"section")}async _requestMutationAction(target,event,mutationName){(target.dataset.id||"bulkaction"===target.dataset.for)&&(event.preventDefault(),"bulkaction"===target.dataset.for?this.reactive.dispatch(mutationName,this.reactive.get("bulk").selection):this.reactive.dispatch(mutationName,[target.dataset.id]))}_requestPermalink(target,event){event.preventDefault(),_modal_copy_to_clipboard.default.create({text:target.getAttribute("href")},(0,_str.getString)("sectionlink","course"))}async _requestCmDuplicate(target,event){var _target$dataset$secti;const cmIds=this._getTargetIds(target);if(0==cmIds.length)return;const sectionId=null!==(_target$dataset$secti=target.dataset.sectionid)&&void 0!==_target$dataset$secti?_target$dataset$secti:null;event.preventDefault(),this.reactive.dispatch("cmDuplicate",cmIds,sectionId)}async _requestCmDelete(target,event){const cmIds=this._getTargetIds(target);if(0==cmIds.length)return;event.preventDefault();let bodyText=null,titleText=null,delegatedsection=null;if(1==cmIds.length){const cmInfo=this.reactive.get("cm",cmIds[0]);cmInfo.hasdelegatedsection?(delegatedsection=cmInfo.delegatesectionid,titleText=this.reactive.getFormatString("cmdelete_subsectiontitle"),bodyText=(0,_str.getString)("sectiondelete_info","core_courseformat",{type:cmInfo.modname,name:cmInfo.name})):(titleText=this.reactive.getFormatString("cmdelete_title"),bodyText=(0,_str.getString)("cmdelete_info","core_courseformat",{type:cmInfo.modname,name:cmInfo.name}))}else titleText=(0,_str.getString)("cmsdelete_title","core_courseformat"),bodyText=(0,_str.getString)("cmsdelete_info","core_courseformat",{count:cmIds.length});const modal=await this._modalBodyRenderedPromise(_modal_delete_cancel.default,{title:titleText,body:bodyText});modal.getRoot().on(_modal_events.default.delete,(e=>{if(e.preventDefault(),modal.destroy(),this.reactive.dispatch("cmDelete",cmIds),1==cmIds.length&&delegatedsection&&target.baseURI.includes("section.php")){let parameters=new URLSearchParams(window.location.search);parameters.has("id")&¶meters.get("id")==delegatedsection&&this._dispatchSectionDelete([delegatedsection],target)}}))}async _requestCmAvailability(target){const cmIds=this._getTargetIds(target);if(0==cmIds.length)return;const data={allowstealth:this.reactive.getExporter().canUseStealth(this.reactive.state,cmIds)},modal=await this._modalBodyRenderedPromise(_modal_save_cancel.default,{title:(0,_str.getString)("availability","core"),body:_templates.default.render("core_courseformat/local/content/cm/availabilitymodal",data),saveButtonText:(0,_str.getString)("apply","core")});this._setupMutationRadioButtonModal(modal,cmIds)}async _requestSectionAvailability(target){const sectionIds=this._getTargetIds(target);if(0==sectionIds.length)return;const title=1==sectionIds.length?"sectionavailability_title":"sectionsavailability_title",modal=await this._modalBodyRenderedPromise(_modal_save_cancel.default,{title:this.reactive.getFormatString(title),body:_templates.default.render("core_courseformat/local/content/section/availabilitymodal",[]),saveButtonText:(0,_str.getString)("apply","core")});this._setupMutationRadioButtonModal(modal,sectionIds)}_setupMutationRadioButtonModal(modal,ids){modal.setButtonDisabled("save",!0);const submitFunction=radio=>{const mutation=null==radio?void 0:radio.value;return!!mutation&&(this.reactive.dispatch(mutation,ids),!0)},modalBody=(0,_normalise.getFirst)(modal.getBody());modalBody.querySelectorAll(this.selectors.OPTIONSRADIO).forEach((radio=>{radio.addEventListener("change",(()=>{modal.setButtonDisabled("save",!1)})),radio.parentNode.addEventListener("click",(()=>{radio.checked=!0,modal.setButtonDisabled("save",!1)})),radio.parentNode.addEventListener("dblclick",(dbClickEvent=>{submitFunction(radio)&&(dbClickEvent.preventDefault(),modal.destroy())}))})),modal.getRoot().on(_modal_events.default.save,(()=>{const radio=modalBody.querySelector("".concat(this.selectors.OPTIONSRADIO,":checked"));submitFunction(radio)}))}_disableLink(element){element&&(element.style.pointerEvents="none",element.style.userSelect="none",element.classList.add(this.classes.DISABLED),element.classList.add(this.classes.ITALIC),element.setAttribute("aria-disabled",!0),element.addEventListener("click",(event=>event.preventDefault())))}_modalBodyRenderedPromise(ModalClass,modalParams){return new Promise(((resolve,reject)=>{ModalClass.create(modalParams).then((modal=>{modal.setRemoveOnClose(!0),modal.getRoot().on(_modal_events.default.bodyRendered,(()=>{resolve(modal)})),void 0!==modalParams.saveButtonText&&modal.setSaveButtonText(modalParams.saveButtonText),void 0!==modalParams.deleteButtonText&&modal.setDeleteButtonText(modalParams.saveButtonText),modal.show()})).catch((()=>{reject("Cannot load modal content")}))}))}_destroyModal(modal,element){modal.hide();const pendingDestroy=new _pending.default("courseformat/actions:destroyModal");element&&element.focus(),setTimeout((()=>{modal.destroy(),pendingDestroy.resolve()}),500)}_getClosestActionMenuToogler(element){const actionMenu=element.closest(this.selectors.ACTIONMENU);if(actionMenu)return actionMenu.querySelector(this.selectors.ACTIONMENUTOGGLER)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=actions.min.js.map \ No newline at end of file diff --git a/public/course/format/amd/build/local/content/actions.min.js.map b/public/course/format/amd/build/local/content/actions.min.js.map index ec207d9ee13..325547d0354 100644 --- a/public/course/format/amd/build/local/content/actions.min.js.map +++ b/public/course/format/amd/build/local/content/actions.min.js.map @@ -1 +1 @@ -{"version":3,"file":"actions.min.js","sources":["../../../src/local/content/actions.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course state actions dispatcher.\n *\n * This module captures all data-dispatch links in the course content and dispatch the proper\n * state mutation, including any confirmation and modal required.\n *\n * @module core_courseformat/local/content/actions\n * @class core_courseformat/local/content/actions\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {eventTypes} from 'core/local/inplace_editable/events';\nimport Collapse from 'theme_boost/bootstrap/collapse';\nimport log from 'core/log';\nimport Modal from 'core/modal';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport ModalDeleteCancel from 'core/modal_delete_cancel';\nimport ModalCopyToClipboard from 'core/modal_copy_to_clipboard';\nimport ModalEvents from 'core/modal_events';\nimport Templates from 'core/templates';\nimport {prefetchStrings} from 'core/prefetch';\nimport {getString} from 'core/str';\nimport {getFirst} from 'core/normalise';\nimport {toggleBulkSelectionAction} from 'core_courseformat/local/content/actions/bulkselection';\nimport Pending from 'core/pending';\nimport ContentTree from 'core_courseformat/local/courseeditor/contenttree';\n\n// Load global strings.\nprefetchStrings('core', ['movecoursesection', 'movecoursemodule', 'confirm', 'delete']);\n\n// Mutations are dispatched by the course content actions.\n// Formats can use this module addActions static method to add custom actions.\n// Direct mutations can be simple strings (mutation) name or functions.\nconst directMutations = {\n sectionHide: 'sectionHide',\n sectionShow: 'sectionShow',\n cmHide: 'cmHide',\n cmShow: 'cmShow',\n cmStealth: 'cmStealth',\n cmMoveRight: 'cmMoveRight',\n cmMoveLeft: 'cmMoveLeft',\n cmNoGroups: 'cmNoGroups',\n cmSeparateGroups: 'cmSeparateGroups',\n cmVisibleGroups: 'cmVisibleGroups',\n};\n\nexport default class extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'content_actions';\n // Default query selectors.\n this.selectors = {\n ACTIONLINK: `[data-action]`,\n // Move modal selectors.\n SECTIONLINK: `[data-for='section']`,\n CMLINK: `[data-for='cm']`,\n SECTIONNODE: `[data-for='sectionnode']`,\n MODALTOGGLER: `[data-bs-toggle='collapse']`,\n ADDSECTION: `[data-action='addSection']`,\n CONTENTTREE: `#destination-selector`,\n ACTIONMENU: `.action-menu`,\n ACTIONMENUTOGGLER: `[data-bs-toggle=\"dropdown\"]`,\n // Availability modal selectors.\n OPTIONSRADIO: `[type='radio']`,\n COURSEADDSECTION: `#course-addsection`,\n ADDSECTIONREGION: `[data-region='section-addsection']`,\n };\n // Component css classes.\n this.classes = {\n DISABLED: `disabled`,\n ITALIC: `fst-italic`,\n DISPLAYNONE: `d-none`,\n };\n }\n\n /**\n * Add extra actions to the module.\n *\n * @param {array} actions array of methods to execute\n */\n static addActions(actions) {\n for (const [action, mutationReference] of Object.entries(actions)) {\n if (typeof mutationReference !== 'function' && typeof mutationReference !== 'string') {\n throw new Error(`${action} action must be a mutation name or a function`);\n }\n directMutations[action] = mutationReference;\n }\n }\n\n /**\n * Initial state ready method.\n */\n stateReady() {\n // Delegate dispatch clicks.\n this.addEventListener(\n this.element,\n 'click',\n this._dispatchClick\n );\n // Any inplace editable update needs state refresh.\n this.addEventListener(\n this.element,\n eventTypes.elementUpdated,\n this._inplaceEditableHandler\n );\n }\n\n _dispatchClick(event) {\n const target = event.target.closest(this.selectors.ACTIONLINK);\n if (!target) {\n return;\n }\n if (target.classList.contains(this.classes.DISABLED)) {\n event.preventDefault();\n return;\n }\n\n // Invoke proper method.\n const actionName = target.dataset.action;\n const methodName = this._actionMethodName(actionName);\n\n if (this[methodName] !== undefined) {\n this[methodName](target, event);\n return;\n }\n\n // Check direct mutations or mutations handlers.\n if (directMutations[actionName] !== undefined) {\n if (typeof directMutations[actionName] === 'function') {\n directMutations[actionName](target, event);\n return;\n }\n this._requestMutationAction(target, event, directMutations[actionName]);\n return;\n }\n }\n\n _actionMethodName(name) {\n const requestName = name.charAt(0).toUpperCase() + name.slice(1);\n return `_request${requestName}`;\n }\n\n /**\n * Handle inplace editable updates.\n *\n * @param {Event} event the triggered event\n * @private\n */\n _inplaceEditableHandler(event) {\n const itemtype = event.detail?.ajaxreturn?.itemtype;\n const itemid = parseInt(event.detail?.ajaxreturn?.itemid);\n if (!Number.isFinite(itemid) || !itemtype) {\n return;\n }\n\n if (itemtype === 'activityname') {\n this.reactive.dispatch('cmState', [itemid]);\n return;\n }\n // Sections uses sectionname for normal sections and sectionnamenl for the no link sections.\n if (itemtype === 'sectionname' || itemtype === 'sectionnamenl') {\n this.reactive.dispatch('sectionState', [itemid]);\n return;\n }\n }\n\n /**\n * Return the ids represented by this element.\n *\n * Depending on the dataset attributes the action could represent a single id\n * or a bulk actions with all the current selected ids.\n *\n * @param {HTMLElement} target\n * @returns {Number[]} array of Ids\n */\n _getTargetIds(target) {\n let ids = [];\n if (target?.dataset?.id) {\n ids.push(target.dataset.id);\n }\n const bulkType = target?.dataset?.bulk;\n if (!bulkType) {\n return ids;\n }\n const bulk = this.reactive.get('bulk');\n if (bulk.enabled && bulk.selectedType === bulkType) {\n ids = [...ids, ...bulk.selection];\n }\n return ids;\n }\n\n /**\n * Handle a move section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestMoveSection(target, event) {\n // Check we have an id.\n const sectionIds = this._getTargetIds(target);\n if (sectionIds.length == 0) {\n return;\n }\n\n event.preventDefault();\n\n const pendingModalReady = new Pending(`courseformat/actions:prepareMoveSectionModal`);\n\n // The section edit menu to refocus on end.\n const editTools = this._getClosestActionMenuToogler(target);\n\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(this.reactive.state);\n let titleText = null;\n\n // Add the target section id and title.\n let sectionInfo = null;\n if (sectionIds.length == 1) {\n sectionInfo = this.reactive.get('section', sectionIds[0]);\n data.sectionid = sectionInfo.id;\n data.sectiontitle = sectionInfo.title;\n data.information = await this.reactive.getFormatString('sectionmove_info', data.sectiontitle);\n titleText = this.reactive.getFormatString('sectionmove_title');\n } else {\n data.information = await this.reactive.getFormatString('sectionsmove_info', sectionIds.length);\n titleText = this.reactive.getFormatString('sectionsmove_title');\n }\n\n\n // Create the modal.\n // Build the modal parameters from the event data.\n const modal = await this._modalBodyRenderedPromise(Modal, {\n title: titleText,\n body: Templates.render('core_courseformat/local/content/movesection', data),\n });\n\n const modalBody = getFirst(modal.getBody());\n\n // Disable current selected section ids.\n sectionIds.forEach(sectionId => {\n const currentElement = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-id='${sectionId}']`);\n this._disableLink(currentElement);\n });\n\n // Setup keyboard navigation.\n new ContentTree(\n modalBody.querySelector(this.selectors.CONTENTTREE),\n {\n SECTION: this.selectors.SECTIONNODE,\n TOGGLER: this.selectors.MODALTOGGLER,\n COLLAPSE: this.selectors.MODALTOGGLER,\n },\n true\n );\n\n // Capture click.\n modalBody.addEventListener('click', (event) => {\n const target = event.target;\n if (!target.matches('a') || target.dataset.for != 'section' || target.dataset.id === undefined) {\n return;\n }\n if (target.getAttribute('aria-disabled')) {\n return;\n }\n event.preventDefault();\n this.reactive.dispatch('sectionMoveAfter', sectionIds, target.dataset.id);\n this._destroyModal(modal, editTools);\n });\n\n pendingModalReady.resolve();\n }\n\n /**\n * Handle a move cm request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestMoveCm(target, event) {\n // Check we have an id.\n const cmIds = this._getTargetIds(target);\n if (cmIds.length == 0) {\n return;\n }\n\n event.preventDefault();\n\n const pendingModalReady = new Pending(`courseformat/actions:prepareMoveCmModal`);\n\n // The section edit menu to refocus on end.\n const editTools = this._getClosestActionMenuToogler(target);\n\n // Collect information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(this.reactive.state);\n\n let titleText = null;\n if (cmIds.length == 1) {\n const cmInfo = this.reactive.get('cm', cmIds[0]);\n data.cmid = cmInfo.id;\n data.cmname = cmInfo.name;\n data.information = await this.reactive.getFormatString('cmmove_info', data.cmname);\n if (cmInfo.hasdelegatedsection) {\n titleText = this.reactive.getFormatString('cmmove_subsectiontitle');\n } else {\n titleText = this.reactive.getFormatString('cmmove_title');\n }\n } else {\n data.information = await this.reactive.getFormatString('cmsmove_info', cmIds.length);\n titleText = this.reactive.getFormatString('cmsmove_title');\n }\n\n // Create the modal.\n // Build the modal parameters from the event data.\n const modal = await this._modalBodyRenderedPromise(Modal, {\n title: titleText,\n body: Templates.render('core_courseformat/local/content/movecm', data),\n });\n\n const modalBody = getFirst(modal.getBody());\n\n // Disable current selected section ids.\n cmIds.forEach(cmId => {\n const currentElement = modalBody.querySelector(`${this.selectors.CMLINK}[data-id='${cmId}']`);\n this._disableLink(currentElement);\n });\n\n // Setup keyboard navigation.\n new ContentTree(\n modalBody.querySelector(this.selectors.CONTENTTREE),\n {\n SECTION: this.selectors.SECTIONNODE,\n TOGGLER: this.selectors.MODALTOGGLER,\n COLLAPSE: this.selectors.MODALTOGGLER,\n ENTER: this.selectors.SECTIONLINK,\n }\n );\n\n cmIds.forEach(cmId => {\n const cmInfo = this.reactive.get('cm', cmId);\n let selector;\n if (!cmInfo.hasdelegatedsection) {\n selector = `${this.selectors.CMLINK}[data-id='${cmId}']`;\n } else {\n selector = `${this.selectors.SECTIONLINK}[data-id='${cmInfo.sectionid}']`;\n }\n const currentElement = modalBody.querySelector(selector);\n this._expandCmMoveModalParentSections(modalBody, currentElement);\n });\n\n modalBody.addEventListener('click', (event) => {\n const target = event.target;\n if (!target.matches('a') || target.dataset.for === undefined || target.dataset.id === undefined) {\n return;\n }\n if (target.getAttribute('aria-disabled')) {\n return;\n }\n event.preventDefault();\n\n let targetSectionId;\n let targetCmId;\n let droppedCmIds = [...cmIds];\n if (target.dataset.for == 'cm') {\n const dropData = exporter.cmDraggableData(this.reactive.state, target.dataset.id);\n targetSectionId = dropData.sectionid;\n targetCmId = dropData.nextcmid;\n } else {\n const section = this.reactive.get('section', target.dataset.id);\n targetSectionId = target.dataset.id;\n targetCmId = section?.cmlist[0];\n }\n const section = this.reactive.get('section', targetSectionId);\n if (section.component) {\n // Remove cmIds which are not allowed to be moved to this delegated section (mostly\n // all other delegated cm).\n droppedCmIds = droppedCmIds.filter(cmId => {\n const cmInfo = this.reactive.get('cm', cmId);\n return !cmInfo.hasdelegatedsection;\n });\n }\n if (droppedCmIds.length === 0) {\n return; // No cm to move.\n }\n this.reactive.dispatch('cmMove', droppedCmIds, targetSectionId, targetCmId);\n this._destroyModal(modal, editTools);\n });\n\n pendingModalReady.resolve();\n }\n\n /**\n * Expand all the modal tree branches that contains the element.\n *\n * @private\n * @param {HTMLElement} modalBody the modal body element\n * @param {HTMLElement} element the element to display\n */\n _expandCmMoveModalParentSections(modalBody, element) {\n const sectionnode = element.closest(this.selectors.SECTIONNODE);\n if (!sectionnode) {\n return;\n }\n\n const toggler = sectionnode.querySelector(this.selectors.MODALTOGGLER);\n let collapsibleId = toggler.dataset.target ?? toggler.getAttribute('href');\n if (collapsibleId) {\n // We cannot be sure we have # in the id element name.\n collapsibleId = collapsibleId.replace('#', '');\n const expandNode = modalBody.querySelector(`#${collapsibleId}`);\n new Collapse(expandNode, {toggle: false}).show();\n }\n\n // Section are a tree structure, we need to expand all the parents.\n this._expandCmMoveModalParentSections(modalBody, sectionnode.parentElement);\n }\n\n /**\n * Handle a create section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestAddSection(target, event) {\n event.preventDefault();\n this.reactive.dispatch('addSection', target.dataset.id ?? 0);\n }\n\n /**\n * Handle a create subsection request.\n *\n * @deprecated since Moodle 5.0 MDL-83469.\n * @todo MDL-83851 This will be deleted in Moodle 6.0.\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestAddModule(target, event) {\n log.debug('AddModule action is deprecated. Use newModule instead');\n event.preventDefault();\n this.reactive.dispatch('addModule', target.dataset.modname, target.dataset.sectionnum, target.dataset.beforemod);\n }\n\n /**\n * Handle a new create subsection request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestNewModule(target, event) {\n event.preventDefault();\n this.reactive.dispatch('newModule', target.dataset.modname, target.dataset.sectionid, target.dataset.beforemod);\n }\n\n /**\n * Handle a delete section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestDeleteSection(target, event) {\n const sectionIds = this._getTargetIds(target);\n if (sectionIds.length == 0) {\n return;\n }\n\n event.preventDefault();\n\n // We don't need confirmation to delete empty sections.\n let needsConfirmation = sectionIds.some(sectionId => {\n const sectionInfo = this.reactive.get('section', sectionId);\n const cmList = sectionInfo.cmlist ?? [];\n return (cmList.length || sectionInfo.hassummary || sectionInfo.rawtitle);\n });\n if (!needsConfirmation) {\n this._dispatchSectionDelete(sectionIds, target);\n return;\n }\n\n let bodyText = null;\n let titleText = null;\n if (sectionIds.length == 1) {\n titleText = this.reactive.getFormatString('sectiondelete_title');\n const sectionInfo = this.reactive.get('section', sectionIds[0]);\n bodyText = this.reactive.getFormatString('sectiondelete_info', {name: sectionInfo.title});\n } else {\n titleText = this.reactive.getFormatString('sectionsdelete_title');\n bodyText = this.reactive.getFormatString('sectionsdelete_info', {count: sectionIds.length});\n }\n\n const modal = await this._modalBodyRenderedPromise(ModalDeleteCancel, {\n title: titleText,\n body: bodyText,\n });\n\n modal.getRoot().on(\n ModalEvents.delete,\n e => {\n // Stop the default save button behaviour which is to close the modal.\n e.preventDefault();\n modal.destroy();\n this._dispatchSectionDelete(sectionIds, target);\n }\n );\n }\n\n /**\n * Dispatch the section delete action and handle the redirection if necessary.\n *\n * @param {Array} sectionIds the IDs of the sections to delete.\n * @param {Element} target the dispatch action element\n */\n async _dispatchSectionDelete(sectionIds, target) {\n await this.reactive.dispatch('sectionDelete', sectionIds);\n if (target.baseURI.includes('section.php')) {\n // Redirect to the course main page if the section is the current page.\n window.location.href = this.reactive.get('course').baseurl;\n }\n }\n\n /**\n * Handle a toggle cm selection.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestToggleSelectionCm(target, event) {\n toggleBulkSelectionAction(this.reactive, target, event, 'cm');\n }\n\n /**\n * Handle a toggle section selection.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestToggleSelectionSection(target, event) {\n toggleBulkSelectionAction(this.reactive, target, event, 'section');\n }\n\n /**\n * Basic mutation action helper.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n * @param {string} mutationName the mutation name\n */\n async _requestMutationAction(target, event, mutationName) {\n if (!target.dataset.id && target.dataset.for !== 'bulkaction') {\n return;\n }\n event.preventDefault();\n if (target.dataset.for === 'bulkaction') {\n // If the mutation is a bulk action we use the current selection.\n this.reactive.dispatch(mutationName, this.reactive.get('bulk').selection);\n } else {\n this.reactive.dispatch(mutationName, [target.dataset.id]);\n }\n }\n\n /**\n * Handle a course permalink modal request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n _requestPermalink(target, event) {\n event.preventDefault();\n ModalCopyToClipboard.create(\n {\n text: target.getAttribute('href'),\n },\n getString('sectionlink', 'course')\n );\n return;\n }\n\n /**\n * Handle a course module duplicate request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestCmDuplicate(target, event) {\n const cmIds = this._getTargetIds(target);\n if (cmIds.length == 0) {\n return;\n }\n const sectionId = target.dataset.sectionid ?? null;\n event.preventDefault();\n this.reactive.dispatch('cmDuplicate', cmIds, sectionId);\n }\n\n /**\n * Handle a delete cm request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestCmDelete(target, event) {\n const cmIds = this._getTargetIds(target);\n if (cmIds.length == 0) {\n return;\n }\n\n event.preventDefault();\n\n let bodyText = null;\n let titleText = null;\n let delegatedsection = null;\n if (cmIds.length == 1) {\n const cmInfo = this.reactive.get('cm', cmIds[0]);\n if (cmInfo.hasdelegatedsection) {\n delegatedsection = cmInfo.delegatesectionid;\n titleText = this.reactive.getFormatString('cmdelete_subsectiontitle');\n bodyText = getString(\n 'sectiondelete_info',\n 'core_courseformat',\n {\n type: cmInfo.modname,\n name: cmInfo.name,\n }\n );\n } else {\n titleText = this.reactive.getFormatString('cmdelete_title');\n bodyText = getString(\n 'cmdelete_info',\n 'core_courseformat',\n {\n type: cmInfo.modname,\n name: cmInfo.name,\n }\n );\n }\n } else {\n titleText = getString('cmsdelete_title', 'core_courseformat');\n bodyText = getString(\n 'cmsdelete_info',\n 'core_courseformat',\n {count: cmIds.length}\n );\n }\n\n const modal = await this._modalBodyRenderedPromise(ModalDeleteCancel, {\n title: titleText,\n body: bodyText,\n });\n\n modal.getRoot().on(\n ModalEvents.delete,\n e => {\n // Stop the default save button behaviour which is to close the modal.\n e.preventDefault();\n modal.destroy();\n this.reactive.dispatch('cmDelete', cmIds);\n if (cmIds.length == 1 && delegatedsection && target.baseURI.includes('section.php')) {\n // Redirect to the course main page if the subsection is the current page.\n let parameters = new URLSearchParams(window.location.search);\n if (parameters.has('id') && parameters.get('id') == delegatedsection) {\n this._dispatchSectionDelete([delegatedsection], target);\n }\n }\n }\n );\n }\n\n /**\n * Handle a cm availability change request.\n *\n * @param {Element} target the dispatch action element\n */\n async _requestCmAvailability(target) {\n const cmIds = this._getTargetIds(target);\n if (cmIds.length == 0) {\n return;\n }\n // Show the availability modal to decide which action to trigger.\n const exporter = this.reactive.getExporter();\n const data = {\n allowstealth: exporter.canUseStealth(this.reactive.state, cmIds),\n };\n const modal = await this._modalBodyRenderedPromise(ModalSaveCancel, {\n title: getString('availability', 'core'),\n body: Templates.render('core_courseformat/local/content/cm/availabilitymodal', data),\n saveButtonText: getString('apply', 'core'),\n });\n\n this._setupMutationRadioButtonModal(modal, cmIds);\n }\n\n /**\n * Handle a section availability change request.\n *\n * @param {Element} target the dispatch action element\n */\n async _requestSectionAvailability(target) {\n const sectionIds = this._getTargetIds(target);\n if (sectionIds.length == 0) {\n return;\n }\n const title = (sectionIds.length == 1) ? 'sectionavailability_title' : 'sectionsavailability_title';\n // Show the availability modal to decide which action to trigger.\n const modal = await this._modalBodyRenderedPromise(ModalSaveCancel, {\n title: this.reactive.getFormatString(title),\n body: Templates.render('core_courseformat/local/content/section/availabilitymodal', []),\n saveButtonText: getString('apply', 'core'),\n });\n\n this._setupMutationRadioButtonModal(modal, sectionIds);\n }\n\n /**\n * Add events to a mutation selector radio buttons modal.\n * @param {Modal} modal\n * @param {Number[]} ids the section or cm ids to apply the mutation\n */\n _setupMutationRadioButtonModal(modal, ids) {\n // The save button is not enabled until the user selects an option.\n modal.setButtonDisabled('save', true);\n\n const submitFunction = (radio) => {\n const mutation = radio?.value;\n if (!mutation) {\n return false;\n }\n this.reactive.dispatch(mutation, ids);\n return true;\n };\n\n const modalBody = getFirst(modal.getBody());\n const radioOptions = modalBody.querySelectorAll(this.selectors.OPTIONSRADIO);\n radioOptions.forEach(radio => {\n radio.addEventListener('change', () => {\n modal.setButtonDisabled('save', false);\n });\n radio.parentNode.addEventListener('click', () => {\n radio.checked = true;\n modal.setButtonDisabled('save', false);\n });\n radio.parentNode.addEventListener('dblclick', dbClickEvent => {\n if (submitFunction(radio)) {\n dbClickEvent.preventDefault();\n modal.destroy();\n }\n });\n });\n\n modal.getRoot().on(\n ModalEvents.save,\n () => {\n const radio = modalBody.querySelector(`${this.selectors.OPTIONSRADIO}:checked`);\n submitFunction(radio);\n }\n );\n }\n\n /**\n * Replace an element with a copy with a different tag name.\n *\n * @param {Element} element the original element\n */\n _disableLink(element) {\n if (element) {\n element.style.pointerEvents = 'none';\n element.style.userSelect = 'none';\n element.classList.add(this.classes.DISABLED);\n element.classList.add(this.classes.ITALIC);\n element.setAttribute('aria-disabled', true);\n element.addEventListener('click', event => event.preventDefault());\n }\n }\n\n /**\n * Render a modal and return a body ready promise.\n *\n * @param {Modal} ModalClass the modal class\n * @param {object} modalParams the modal params\n * @return {Promise} the modal body ready promise\n */\n _modalBodyRenderedPromise(ModalClass, modalParams) {\n return new Promise((resolve, reject) => {\n ModalClass.create(modalParams).then((modal) => {\n modal.setRemoveOnClose(true);\n // Handle body loading event.\n modal.getRoot().on(ModalEvents.bodyRendered, () => {\n resolve(modal);\n });\n // Configure some extra modal params.\n if (modalParams.saveButtonText !== undefined) {\n modal.setSaveButtonText(modalParams.saveButtonText);\n }\n if (modalParams.deleteButtonText !== undefined) {\n modal.setDeleteButtonText(modalParams.saveButtonText);\n }\n modal.show();\n return;\n }).catch(() => {\n reject(`Cannot load modal content`);\n });\n });\n }\n\n /**\n * Hide and later destroy a modal.\n *\n * Behat will fail if we remove the modal while some boostrap collapse is executing.\n *\n * @param {Modal} modal\n * @param {HTMLElement} element the dom element to focus on.\n */\n _destroyModal(modal, element) {\n modal.hide();\n const pendingDestroy = new Pending(`courseformat/actions:destroyModal`);\n if (element) {\n element.focus();\n }\n setTimeout(() =>{\n modal.destroy();\n pendingDestroy.resolve();\n }, 500);\n }\n\n /**\n * Get the closest actions menu toggler to an action element.\n *\n * @param {HTMLElement} element the action link element\n * @returns {HTMLElement|undefined}\n */\n _getClosestActionMenuToogler(element) {\n const actionMenu = element.closest(this.selectors.ACTIONMENU);\n if (!actionMenu) {\n return undefined;\n }\n return actionMenu.querySelector(this.selectors.ACTIONMENUTOGGLER);\n }\n}\n"],"names":["directMutations","sectionHide","sectionShow","cmHide","cmShow","cmStealth","cmMoveRight","cmMoveLeft","cmNoGroups","cmSeparateGroups","cmVisibleGroups","BaseComponent","create","name","selectors","ACTIONLINK","SECTIONLINK","CMLINK","SECTIONNODE","MODALTOGGLER","ADDSECTION","CONTENTTREE","ACTIONMENU","ACTIONMENUTOGGLER","OPTIONSRADIO","COURSEADDSECTION","ADDSECTIONREGION","classes","DISABLED","ITALIC","DISPLAYNONE","actions","action","mutationReference","Object","entries","Error","stateReady","addEventListener","this","element","_dispatchClick","eventTypes","elementUpdated","_inplaceEditableHandler","event","target","closest","classList","contains","preventDefault","actionName","dataset","methodName","_actionMethodName","undefined","_requestMutationAction","requestName","charAt","toUpperCase","slice","itemtype","detail","_event$detail","ajaxreturn","_event$detail$ajaxret","itemid","parseInt","_event$detail2","_event$detail2$ajaxre","Number","isFinite","reactive","dispatch","_getTargetIds","ids","_target$dataset","id","push","bulkType","_target$dataset2","bulk","get","enabled","selectedType","selection","sectionIds","length","pendingModalReady","Pending","editTools","_getClosestActionMenuToogler","data","getExporter","course","state","titleText","sectionInfo","sectionid","sectiontitle","title","information","getFormatString","modal","_modalBodyRenderedPromise","Modal","body","Templates","render","modalBody","getBody","forEach","sectionId","currentElement","querySelector","_disableLink","ContentTree","SECTION","TOGGLER","COLLAPSE","matches","for","getAttribute","_destroyModal","resolve","cmIds","exporter","cmInfo","cmid","cmname","hasdelegatedsection","cmId","ENTER","selector","_expandCmMoveModalParentSections","targetSectionId","targetCmId","droppedCmIds","dropData","cmDraggableData","nextcmid","section","cmlist","component","filter","sectionnode","toggler","collapsibleId","replace","expandNode","Collapse","toggle","show","parentElement","debug","modname","sectionnum","beforemod","some","hassummary","rawtitle","_dispatchSectionDelete","bodyText","count","ModalDeleteCancel","getRoot","on","ModalEvents","delete","e","destroy","baseURI","includes","window","location","href","baseurl","mutationName","_requestPermalink","text","delegatedsection","delegatesectionid","type","parameters","URLSearchParams","search","has","allowstealth","canUseStealth","ModalSaveCancel","saveButtonText","_setupMutationRadioButtonModal","setButtonDisabled","submitFunction","radio","mutation","value","querySelectorAll","parentNode","checked","dbClickEvent","save","style","pointerEvents","userSelect","add","setAttribute","ModalClass","modalParams","Promise","reject","then","setRemoveOnClose","bodyRendered","setSaveButtonText","deleteButtonText","setDeleteButtonText","catch","hide","pendingDestroy","focus","setTimeout","actionMenu"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"actions.min.js","sources":["../../../src/local/content/actions.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course state actions dispatcher.\n *\n * This module captures all data-dispatch links in the course content and dispatch the proper\n * state mutation, including any confirmation and modal required.\n *\n * @module core_courseformat/local/content/actions\n * @class core_courseformat/local/content/actions\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {eventTypes} from 'core/local/inplace_editable/events';\nimport Collapse from 'theme_boost/bootstrap/collapse';\nimport log from 'core/log';\nimport Modal from 'core/modal';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport ModalDeleteCancel from 'core/modal_delete_cancel';\nimport ModalCopyToClipboard from 'core/modal_copy_to_clipboard';\nimport ModalEvents from 'core/modal_events';\nimport Templates from 'core/templates';\nimport {prefetchStrings} from 'core/prefetch';\nimport {getString} from 'core/str';\nimport {getFirst} from 'core/normalise';\nimport {toggleBulkSelectionAction} from 'core_courseformat/local/content/actions/bulkselection';\nimport Pending from 'core/pending';\nimport ContentTree from 'core_courseformat/local/courseeditor/contenttree';\n\n// Load global strings.\nprefetchStrings('core', ['movecoursesection', 'movecoursemodule', 'confirm', 'delete']);\n\n// Mutations are dispatched by the course content actions.\n// Formats can use this module addActions static method to add custom actions.\n// Direct mutations can be simple strings (mutation) name or functions.\nconst directMutations = {\n sectionHide: 'sectionHide',\n sectionShow: 'sectionShow',\n cmHide: 'cmHide',\n cmShow: 'cmShow',\n cmStealth: 'cmStealth',\n cmMoveRight: 'cmMoveRight',\n cmMoveLeft: 'cmMoveLeft',\n cmNoGroups: 'cmNoGroups',\n cmSeparateGroups: 'cmSeparateGroups',\n cmVisibleGroups: 'cmVisibleGroups',\n};\n\nexport default class extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'content_actions';\n // Default query selectors.\n this.selectors = {\n ACTIONLINK: `[data-action]`,\n // Move modal selectors.\n SECTIONLINK: `[data-for='section']`,\n CMLINK: `[data-for='cm']`,\n SECTIONNODE: `[data-for='sectionnode']`,\n MODALTOGGLER: `[data-bs-toggle='collapse']`,\n ADDSECTION: `[data-action='addSection']`,\n CONTENTTREE: `#destination-selector`,\n ACTIONMENU: `.action-menu`,\n ACTIONMENUTOGGLER: `[data-bs-toggle=\"dropdown\"]`,\n // Availability modal selectors.\n OPTIONSRADIO: `[type='radio']`,\n COURSEADDSECTION: `#course-addsection`,\n ADDSECTIONREGION: `[data-region='section-addsection']`,\n };\n // Component css classes.\n this.classes = {\n DISABLED: `disabled`,\n ITALIC: `fst-italic`,\n DISPLAYNONE: `d-none`,\n };\n }\n\n /**\n * Add extra actions to the module.\n *\n * @param {array} actions array of methods to execute\n */\n static addActions(actions) {\n for (const [action, mutationReference] of Object.entries(actions)) {\n if (typeof mutationReference !== 'function' && typeof mutationReference !== 'string') {\n throw new Error(`${action} action must be a mutation name or a function`);\n }\n directMutations[action] = mutationReference;\n }\n }\n\n /**\n * Initial state ready method.\n */\n stateReady() {\n // Delegate dispatch clicks.\n this.addEventListener(\n this.element,\n 'click',\n this._dispatchClick\n );\n // Any inplace editable update needs state refresh.\n this.addEventListener(\n this.element,\n eventTypes.elementUpdated,\n this._inplaceEditableHandler\n );\n }\n\n _dispatchClick(event) {\n const target = event.target.closest(this.selectors.ACTIONLINK);\n if (!target) {\n return;\n }\n if (target.classList.contains(this.classes.DISABLED)) {\n event.preventDefault();\n return;\n }\n\n // Invoke proper method.\n const actionName = target.dataset.action;\n const methodName = this._actionMethodName(actionName);\n\n if (this[methodName] !== undefined) {\n this[methodName](target, event);\n return;\n }\n\n // Check direct mutations or mutations handlers.\n if (directMutations[actionName] !== undefined) {\n if (typeof directMutations[actionName] === 'function') {\n directMutations[actionName](target, event);\n return;\n }\n this._requestMutationAction(target, event, directMutations[actionName]);\n return;\n }\n }\n\n _actionMethodName(name) {\n const requestName = name.charAt(0).toUpperCase() + name.slice(1);\n return `_request${requestName}`;\n }\n\n /**\n * Handle inplace editable updates.\n *\n * @param {Event} event the triggered event\n * @private\n */\n _inplaceEditableHandler(event) {\n const itemtype = event.detail?.ajaxreturn?.itemtype;\n const itemid = parseInt(event.detail?.ajaxreturn?.itemid);\n if (!Number.isFinite(itemid) || !itemtype) {\n return;\n }\n\n if (itemtype === 'activityname') {\n this.reactive.dispatch('cmState', [itemid]);\n return;\n }\n // Sections uses sectionname for normal sections and sectionnamenl for the no link sections.\n if (itemtype === 'sectionname' || itemtype === 'sectionnamenl') {\n this.reactive.dispatch('sectionState', [itemid]);\n return;\n }\n }\n\n /**\n * Return the ids represented by this element.\n *\n * Depending on the dataset attributes the action could represent a single id\n * or a bulk actions with all the current selected ids.\n *\n * @param {HTMLElement} target\n * @returns {Number[]} array of Ids\n */\n _getTargetIds(target) {\n let ids = [];\n if (target?.dataset?.id) {\n ids.push(target.dataset.id);\n }\n const bulkType = target?.dataset?.bulk;\n if (!bulkType) {\n return ids;\n }\n const bulk = this.reactive.get('bulk');\n if (bulk.enabled && bulk.selectedType === bulkType) {\n ids = [...ids, ...bulk.selection];\n }\n return ids;\n }\n\n /**\n * Handle a move section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestMoveSection(target, event) {\n // Check we have an id.\n const sectionIds = this._getTargetIds(target);\n if (sectionIds.length == 0) {\n return;\n }\n\n event.preventDefault();\n\n const pendingModalReady = new Pending(`courseformat/actions:prepareMoveSectionModal`);\n\n // The section edit menu to refocus on end.\n const editTools = this._getClosestActionMenuToogler(target);\n\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(this.reactive.state);\n let titleText = null;\n\n // Add the target section id and title.\n let sectionInfo = null;\n if (sectionIds.length == 1) {\n sectionInfo = this.reactive.get('section', sectionIds[0]);\n data.sectionid = sectionInfo.id;\n data.sectiontitle = sectionInfo.title;\n data.information = await this.reactive.getFormatString('sectionmove_info', data.sectiontitle);\n titleText = this.reactive.getFormatString('sectionmove_title');\n } else {\n data.information = await this.reactive.getFormatString('sectionsmove_info', sectionIds.length);\n titleText = this.reactive.getFormatString('sectionsmove_title');\n }\n\n\n // Create the modal.\n // Build the modal parameters from the event data.\n const modal = await this._modalBodyRenderedPromise(Modal, {\n title: titleText,\n body: Templates.render('core_courseformat/local/content/movesection', data),\n });\n\n const modalBody = getFirst(modal.getBody());\n\n // Disable current selected section ids.\n sectionIds.forEach(sectionId => {\n const currentElement = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-id='${sectionId}']`);\n this._disableLink(currentElement);\n });\n\n // Setup keyboard navigation.\n new ContentTree(\n modalBody.querySelector(this.selectors.CONTENTTREE),\n {\n SECTION: this.selectors.SECTIONNODE,\n TOGGLER: this.selectors.MODALTOGGLER,\n COLLAPSE: this.selectors.MODALTOGGLER,\n },\n true\n );\n\n // Capture click.\n modalBody.addEventListener('click', (event) => {\n const target = event.target.closest('a');\n if (!target || target.dataset.for != 'section' || target.dataset.id === undefined) {\n return;\n }\n if (target.getAttribute('aria-disabled')) {\n return;\n }\n event.preventDefault();\n this.reactive.dispatch('sectionMoveAfter', sectionIds, target.dataset.id);\n this._destroyModal(modal, editTools);\n });\n\n pendingModalReady.resolve();\n }\n\n /**\n * Handle a move cm request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestMoveCm(target, event) {\n // Check we have an id.\n const cmIds = this._getTargetIds(target);\n if (cmIds.length == 0) {\n return;\n }\n\n event.preventDefault();\n\n const pendingModalReady = new Pending(`courseformat/actions:prepareMoveCmModal`);\n\n // The section edit menu to refocus on end.\n const editTools = this._getClosestActionMenuToogler(target);\n\n // Collect information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(this.reactive.state);\n\n let titleText = null;\n if (cmIds.length == 1) {\n const cmInfo = this.reactive.get('cm', cmIds[0]);\n data.cmid = cmInfo.id;\n data.cmname = cmInfo.name;\n data.information = await this.reactive.getFormatString('cmmove_info', data.cmname);\n if (cmInfo.hasdelegatedsection) {\n titleText = this.reactive.getFormatString('cmmove_subsectiontitle');\n } else {\n titleText = this.reactive.getFormatString('cmmove_title');\n }\n } else {\n data.information = await this.reactive.getFormatString('cmsmove_info', cmIds.length);\n titleText = this.reactive.getFormatString('cmsmove_title');\n }\n\n // Create the modal.\n // Build the modal parameters from the event data.\n const modal = await this._modalBodyRenderedPromise(Modal, {\n title: titleText,\n body: Templates.render('core_courseformat/local/content/movecm', data),\n });\n\n const modalBody = getFirst(modal.getBody());\n\n // Disable current selected section ids.\n cmIds.forEach(cmId => {\n const currentElement = modalBody.querySelector(`${this.selectors.CMLINK}[data-id='${cmId}']`);\n this._disableLink(currentElement);\n });\n\n // Setup keyboard navigation.\n new ContentTree(\n modalBody.querySelector(this.selectors.CONTENTTREE),\n {\n SECTION: this.selectors.SECTIONNODE,\n TOGGLER: this.selectors.MODALTOGGLER,\n COLLAPSE: this.selectors.MODALTOGGLER,\n ENTER: this.selectors.SECTIONLINK,\n }\n );\n\n cmIds.forEach(cmId => {\n const cmInfo = this.reactive.get('cm', cmId);\n let selector;\n if (!cmInfo.hasdelegatedsection) {\n selector = `${this.selectors.CMLINK}[data-id='${cmId}']`;\n } else {\n selector = `${this.selectors.SECTIONLINK}[data-id='${cmInfo.sectionid}']`;\n }\n const currentElement = modalBody.querySelector(selector);\n this._expandCmMoveModalParentSections(modalBody, currentElement);\n });\n\n modalBody.addEventListener('click', (event) => {\n const target = event.target.closest('a');\n if (!target || target.dataset.for === undefined || target.dataset.id === undefined) {\n return;\n }\n if (target.getAttribute('aria-disabled')) {\n return;\n }\n event.preventDefault();\n\n let targetSectionId;\n let targetCmId;\n let droppedCmIds = [...cmIds];\n if (target.dataset.for == 'cm') {\n const dropData = exporter.cmDraggableData(this.reactive.state, target.dataset.id);\n targetSectionId = dropData.sectionid;\n targetCmId = dropData.nextcmid;\n } else {\n const section = this.reactive.get('section', target.dataset.id);\n targetSectionId = target.dataset.id;\n targetCmId = section?.cmlist[0];\n }\n const section = this.reactive.get('section', targetSectionId);\n if (section.component) {\n // Remove cmIds which are not allowed to be moved to this delegated section (mostly\n // all other delegated cm).\n droppedCmIds = droppedCmIds.filter(cmId => {\n const cmInfo = this.reactive.get('cm', cmId);\n return !cmInfo.hasdelegatedsection;\n });\n }\n if (droppedCmIds.length === 0) {\n return; // No cm to move.\n }\n this.reactive.dispatch('cmMove', droppedCmIds, targetSectionId, targetCmId);\n this._destroyModal(modal, editTools);\n });\n\n pendingModalReady.resolve();\n }\n\n /**\n * Expand all the modal tree branches that contains the element.\n *\n * @private\n * @param {HTMLElement} modalBody the modal body element\n * @param {HTMLElement} element the element to display\n */\n _expandCmMoveModalParentSections(modalBody, element) {\n const sectionnode = element.closest(this.selectors.SECTIONNODE);\n if (!sectionnode) {\n return;\n }\n\n const toggler = sectionnode.querySelector(this.selectors.MODALTOGGLER);\n let collapsibleId = toggler.dataset.target ?? toggler.getAttribute('href');\n if (collapsibleId) {\n // We cannot be sure we have # in the id element name.\n collapsibleId = collapsibleId.replace('#', '');\n const expandNode = modalBody.querySelector(`#${collapsibleId}`);\n new Collapse(expandNode, {toggle: false}).show();\n }\n\n // Section are a tree structure, we need to expand all the parents.\n this._expandCmMoveModalParentSections(modalBody, sectionnode.parentElement);\n }\n\n /**\n * Handle a create section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestAddSection(target, event) {\n event.preventDefault();\n this.reactive.dispatch('addSection', target.dataset.id ?? 0);\n }\n\n /**\n * Handle a create subsection request.\n *\n * @deprecated since Moodle 5.0 MDL-83469.\n * @todo MDL-83851 This will be deleted in Moodle 6.0.\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestAddModule(target, event) {\n log.debug('AddModule action is deprecated. Use newModule instead');\n event.preventDefault();\n this.reactive.dispatch('addModule', target.dataset.modname, target.dataset.sectionnum, target.dataset.beforemod);\n }\n\n /**\n * Handle a new create subsection request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestNewModule(target, event) {\n event.preventDefault();\n this.reactive.dispatch('newModule', target.dataset.modname, target.dataset.sectionid, target.dataset.beforemod);\n }\n\n /**\n * Handle a delete section request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestDeleteSection(target, event) {\n const sectionIds = this._getTargetIds(target);\n if (sectionIds.length == 0) {\n return;\n }\n\n event.preventDefault();\n\n // We don't need confirmation to delete empty sections.\n let needsConfirmation = sectionIds.some(sectionId => {\n const sectionInfo = this.reactive.get('section', sectionId);\n const cmList = sectionInfo.cmlist ?? [];\n return (cmList.length || sectionInfo.hassummary || sectionInfo.rawtitle);\n });\n if (!needsConfirmation) {\n this._dispatchSectionDelete(sectionIds, target);\n return;\n }\n\n let bodyText = null;\n let titleText = null;\n if (sectionIds.length == 1) {\n titleText = this.reactive.getFormatString('sectiondelete_title');\n const sectionInfo = this.reactive.get('section', sectionIds[0]);\n bodyText = this.reactive.getFormatString('sectiondelete_info', {name: sectionInfo.title});\n } else {\n titleText = this.reactive.getFormatString('sectionsdelete_title');\n bodyText = this.reactive.getFormatString('sectionsdelete_info', {count: sectionIds.length});\n }\n\n const modal = await this._modalBodyRenderedPromise(ModalDeleteCancel, {\n title: titleText,\n body: bodyText,\n });\n\n modal.getRoot().on(\n ModalEvents.delete,\n e => {\n // Stop the default save button behaviour which is to close the modal.\n e.preventDefault();\n modal.destroy();\n this._dispatchSectionDelete(sectionIds, target);\n }\n );\n }\n\n /**\n * Dispatch the section delete action and handle the redirection if necessary.\n *\n * @param {Array} sectionIds the IDs of the sections to delete.\n * @param {Element} target the dispatch action element\n */\n async _dispatchSectionDelete(sectionIds, target) {\n await this.reactive.dispatch('sectionDelete', sectionIds);\n if (target.baseURI.includes('section.php')) {\n // Redirect to the course main page if the section is the current page.\n window.location.href = this.reactive.get('course').baseurl;\n }\n }\n\n /**\n * Handle a toggle cm selection.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestToggleSelectionCm(target, event) {\n toggleBulkSelectionAction(this.reactive, target, event, 'cm');\n }\n\n /**\n * Handle a toggle section selection.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestToggleSelectionSection(target, event) {\n toggleBulkSelectionAction(this.reactive, target, event, 'section');\n }\n\n /**\n * Basic mutation action helper.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n * @param {string} mutationName the mutation name\n */\n async _requestMutationAction(target, event, mutationName) {\n if (!target.dataset.id && target.dataset.for !== 'bulkaction') {\n return;\n }\n event.preventDefault();\n if (target.dataset.for === 'bulkaction') {\n // If the mutation is a bulk action we use the current selection.\n this.reactive.dispatch(mutationName, this.reactive.get('bulk').selection);\n } else {\n this.reactive.dispatch(mutationName, [target.dataset.id]);\n }\n }\n\n /**\n * Handle a course permalink modal request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n _requestPermalink(target, event) {\n event.preventDefault();\n ModalCopyToClipboard.create(\n {\n text: target.getAttribute('href'),\n },\n getString('sectionlink', 'course')\n );\n return;\n }\n\n /**\n * Handle a course module duplicate request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestCmDuplicate(target, event) {\n const cmIds = this._getTargetIds(target);\n if (cmIds.length == 0) {\n return;\n }\n const sectionId = target.dataset.sectionid ?? null;\n event.preventDefault();\n this.reactive.dispatch('cmDuplicate', cmIds, sectionId);\n }\n\n /**\n * Handle a delete cm request.\n *\n * @param {Element} target the dispatch action element\n * @param {Event} event the triggered event\n */\n async _requestCmDelete(target, event) {\n const cmIds = this._getTargetIds(target);\n if (cmIds.length == 0) {\n return;\n }\n\n event.preventDefault();\n\n let bodyText = null;\n let titleText = null;\n let delegatedsection = null;\n if (cmIds.length == 1) {\n const cmInfo = this.reactive.get('cm', cmIds[0]);\n if (cmInfo.hasdelegatedsection) {\n delegatedsection = cmInfo.delegatesectionid;\n titleText = this.reactive.getFormatString('cmdelete_subsectiontitle');\n bodyText = getString(\n 'sectiondelete_info',\n 'core_courseformat',\n {\n type: cmInfo.modname,\n name: cmInfo.name,\n }\n );\n } else {\n titleText = this.reactive.getFormatString('cmdelete_title');\n bodyText = getString(\n 'cmdelete_info',\n 'core_courseformat',\n {\n type: cmInfo.modname,\n name: cmInfo.name,\n }\n );\n }\n } else {\n titleText = getString('cmsdelete_title', 'core_courseformat');\n bodyText = getString(\n 'cmsdelete_info',\n 'core_courseformat',\n {count: cmIds.length}\n );\n }\n\n const modal = await this._modalBodyRenderedPromise(ModalDeleteCancel, {\n title: titleText,\n body: bodyText,\n });\n\n modal.getRoot().on(\n ModalEvents.delete,\n e => {\n // Stop the default save button behaviour which is to close the modal.\n e.preventDefault();\n modal.destroy();\n this.reactive.dispatch('cmDelete', cmIds);\n if (cmIds.length == 1 && delegatedsection && target.baseURI.includes('section.php')) {\n // Redirect to the course main page if the subsection is the current page.\n let parameters = new URLSearchParams(window.location.search);\n if (parameters.has('id') && parameters.get('id') == delegatedsection) {\n this._dispatchSectionDelete([delegatedsection], target);\n }\n }\n }\n );\n }\n\n /**\n * Handle a cm availability change request.\n *\n * @param {Element} target the dispatch action element\n */\n async _requestCmAvailability(target) {\n const cmIds = this._getTargetIds(target);\n if (cmIds.length == 0) {\n return;\n }\n // Show the availability modal to decide which action to trigger.\n const exporter = this.reactive.getExporter();\n const data = {\n allowstealth: exporter.canUseStealth(this.reactive.state, cmIds),\n };\n const modal = await this._modalBodyRenderedPromise(ModalSaveCancel, {\n title: getString('availability', 'core'),\n body: Templates.render('core_courseformat/local/content/cm/availabilitymodal', data),\n saveButtonText: getString('apply', 'core'),\n });\n\n this._setupMutationRadioButtonModal(modal, cmIds);\n }\n\n /**\n * Handle a section availability change request.\n *\n * @param {Element} target the dispatch action element\n */\n async _requestSectionAvailability(target) {\n const sectionIds = this._getTargetIds(target);\n if (sectionIds.length == 0) {\n return;\n }\n const title = (sectionIds.length == 1) ? 'sectionavailability_title' : 'sectionsavailability_title';\n // Show the availability modal to decide which action to trigger.\n const modal = await this._modalBodyRenderedPromise(ModalSaveCancel, {\n title: this.reactive.getFormatString(title),\n body: Templates.render('core_courseformat/local/content/section/availabilitymodal', []),\n saveButtonText: getString('apply', 'core'),\n });\n\n this._setupMutationRadioButtonModal(modal, sectionIds);\n }\n\n /**\n * Add events to a mutation selector radio buttons modal.\n * @param {Modal} modal\n * @param {Number[]} ids the section or cm ids to apply the mutation\n */\n _setupMutationRadioButtonModal(modal, ids) {\n // The save button is not enabled until the user selects an option.\n modal.setButtonDisabled('save', true);\n\n const submitFunction = (radio) => {\n const mutation = radio?.value;\n if (!mutation) {\n return false;\n }\n this.reactive.dispatch(mutation, ids);\n return true;\n };\n\n const modalBody = getFirst(modal.getBody());\n const radioOptions = modalBody.querySelectorAll(this.selectors.OPTIONSRADIO);\n radioOptions.forEach(radio => {\n radio.addEventListener('change', () => {\n modal.setButtonDisabled('save', false);\n });\n radio.parentNode.addEventListener('click', () => {\n radio.checked = true;\n modal.setButtonDisabled('save', false);\n });\n radio.parentNode.addEventListener('dblclick', dbClickEvent => {\n if (submitFunction(radio)) {\n dbClickEvent.preventDefault();\n modal.destroy();\n }\n });\n });\n\n modal.getRoot().on(\n ModalEvents.save,\n () => {\n const radio = modalBody.querySelector(`${this.selectors.OPTIONSRADIO}:checked`);\n submitFunction(radio);\n }\n );\n }\n\n /**\n * Replace an element with a copy with a different tag name.\n *\n * @param {Element} element the original element\n */\n _disableLink(element) {\n if (element) {\n element.style.pointerEvents = 'none';\n element.style.userSelect = 'none';\n element.classList.add(this.classes.DISABLED);\n element.classList.add(this.classes.ITALIC);\n element.setAttribute('aria-disabled', true);\n element.addEventListener('click', event => event.preventDefault());\n }\n }\n\n /**\n * Render a modal and return a body ready promise.\n *\n * @param {Modal} ModalClass the modal class\n * @param {object} modalParams the modal params\n * @return {Promise} the modal body ready promise\n */\n _modalBodyRenderedPromise(ModalClass, modalParams) {\n return new Promise((resolve, reject) => {\n ModalClass.create(modalParams).then((modal) => {\n modal.setRemoveOnClose(true);\n // Handle body loading event.\n modal.getRoot().on(ModalEvents.bodyRendered, () => {\n resolve(modal);\n });\n // Configure some extra modal params.\n if (modalParams.saveButtonText !== undefined) {\n modal.setSaveButtonText(modalParams.saveButtonText);\n }\n if (modalParams.deleteButtonText !== undefined) {\n modal.setDeleteButtonText(modalParams.saveButtonText);\n }\n modal.show();\n return;\n }).catch(() => {\n reject(`Cannot load modal content`);\n });\n });\n }\n\n /**\n * Hide and later destroy a modal.\n *\n * Behat will fail if we remove the modal while some boostrap collapse is executing.\n *\n * @param {Modal} modal\n * @param {HTMLElement} element the dom element to focus on.\n */\n _destroyModal(modal, element) {\n modal.hide();\n const pendingDestroy = new Pending(`courseformat/actions:destroyModal`);\n if (element) {\n element.focus();\n }\n setTimeout(() =>{\n modal.destroy();\n pendingDestroy.resolve();\n }, 500);\n }\n\n /**\n * Get the closest actions menu toggler to an action element.\n *\n * @param {HTMLElement} element the action link element\n * @returns {HTMLElement|undefined}\n */\n _getClosestActionMenuToogler(element) {\n const actionMenu = element.closest(this.selectors.ACTIONMENU);\n if (!actionMenu) {\n return undefined;\n }\n return actionMenu.querySelector(this.selectors.ACTIONMENUTOGGLER);\n }\n}\n"],"names":["directMutations","sectionHide","sectionShow","cmHide","cmShow","cmStealth","cmMoveRight","cmMoveLeft","cmNoGroups","cmSeparateGroups","cmVisibleGroups","BaseComponent","create","name","selectors","ACTIONLINK","SECTIONLINK","CMLINK","SECTIONNODE","MODALTOGGLER","ADDSECTION","CONTENTTREE","ACTIONMENU","ACTIONMENUTOGGLER","OPTIONSRADIO","COURSEADDSECTION","ADDSECTIONREGION","classes","DISABLED","ITALIC","DISPLAYNONE","actions","action","mutationReference","Object","entries","Error","stateReady","addEventListener","this","element","_dispatchClick","eventTypes","elementUpdated","_inplaceEditableHandler","event","target","closest","classList","contains","preventDefault","actionName","dataset","methodName","_actionMethodName","undefined","_requestMutationAction","requestName","charAt","toUpperCase","slice","itemtype","detail","_event$detail","ajaxreturn","_event$detail$ajaxret","itemid","parseInt","_event$detail2","_event$detail2$ajaxre","Number","isFinite","reactive","dispatch","_getTargetIds","ids","_target$dataset","id","push","bulkType","_target$dataset2","bulk","get","enabled","selectedType","selection","sectionIds","length","pendingModalReady","Pending","editTools","_getClosestActionMenuToogler","data","getExporter","course","state","titleText","sectionInfo","sectionid","sectiontitle","title","information","getFormatString","modal","_modalBodyRenderedPromise","Modal","body","Templates","render","modalBody","getBody","forEach","sectionId","currentElement","querySelector","_disableLink","ContentTree","SECTION","TOGGLER","COLLAPSE","for","getAttribute","_destroyModal","resolve","cmIds","exporter","cmInfo","cmid","cmname","hasdelegatedsection","cmId","ENTER","selector","_expandCmMoveModalParentSections","targetSectionId","targetCmId","droppedCmIds","dropData","cmDraggableData","nextcmid","section","cmlist","component","filter","sectionnode","toggler","collapsibleId","replace","expandNode","Collapse","toggle","show","parentElement","debug","modname","sectionnum","beforemod","some","hassummary","rawtitle","_dispatchSectionDelete","bodyText","count","ModalDeleteCancel","getRoot","on","ModalEvents","delete","e","destroy","baseURI","includes","window","location","href","baseurl","mutationName","_requestPermalink","text","delegatedsection","delegatesectionid","type","parameters","URLSearchParams","search","has","allowstealth","canUseStealth","ModalSaveCancel","saveButtonText","_setupMutationRadioButtonModal","setButtonDisabled","submitFunction","radio","mutation","value","querySelectorAll","parentNode","checked","dbClickEvent","save","style","pointerEvents","userSelect","add","setAttribute","ModalClass","modalParams","Promise","reject","then","setRemoveOnClose","bodyRendered","setSaveButtonText","deleteButtonText","setDeleteButtonText","catch","hide","pendingDestroy","focus","setTimeout","actionMenu"],"mappings":"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"} \ No newline at end of file diff --git a/public/course/format/amd/src/local/content/actions.js b/public/course/format/amd/src/local/content/actions.js index 1a138aaf493..e238279ea70 100644 --- a/public/course/format/amd/src/local/content/actions.js +++ b/public/course/format/amd/src/local/content/actions.js @@ -277,8 +277,8 @@ export default class extends BaseComponent { // Capture click. modalBody.addEventListener('click', (event) => { - const target = event.target; - if (!target.matches('a') || target.dataset.for != 'section' || target.dataset.id === undefined) { + const target = event.target.closest('a'); + if (!target || target.dataset.for != 'section' || target.dataset.id === undefined) { return; } if (target.getAttribute('aria-disabled')) { @@ -371,8 +371,8 @@ export default class extends BaseComponent { }); modalBody.addEventListener('click', (event) => { - const target = event.target; - if (!target.matches('a') || target.dataset.for === undefined || target.dataset.id === undefined) { + const target = event.target.closest('a'); + if (!target || target.dataset.for === undefined || target.dataset.id === undefined) { return; } if (target.getAttribute('aria-disabled')) {