Merge branch 'MDL-74989-master' of https://github.com/ferranrecio/moodle

This commit is contained in:
Paul Holden
2023-01-03 12:33:45 +00:00
34 changed files with 222 additions and 46 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -59,7 +59,7 @@ define(
// component compatible formats and the default actions.js won't be necessary anymore.
// Meanwhile, we filter the migrated actions.
const componentActions = [
'moveSection', 'moveCm', 'addSection', 'deleteSection', 'sectionHide', 'sectionShow',
'moveSection', 'moveCm', 'addSection', 'deleteSection', 'cmDelete', 'sectionHide', 'sectionShow',
'cmHide', 'cmShow', 'cmStealth', 'sectionHighlight', 'sectionUnhighlight',
];
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -8,6 +8,6 @@ define("core_courseformat/local/courseindex/cm",["exports","core_courseformat/lo
* @class core_courseformat/local/courseindex/cm
* @copyright 2021 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_dndcmitem=_interopRequireDefault(_dndcmitem),_templates=_interopRequireDefault(_templates),_prefetch=_interopRequireDefault(_prefetch),_config=_interopRequireDefault(_config);_prefetch.default.prefetchTemplate("core_courseformat/local/courseindex/cmcompletion");class Component extends _dndcmitem.default{create(){this.name="courseindex_cm",this.selectors={CM_NAME:"[data-for='cm_name']",CM_COMPLETION:"[data-for='cm_completion']"},this.classes={CMHIDDEN:"dimmed",LOCKED:"editinprogress",RESTRICTIONS:"restrictions",PAGEITEM:"pageitem"},this.id=this.element.dataset.id}static init(target,selectors){return new Component({element:document.getElementById(target),selectors:selectors})}stateReady(state){this.configDragDrop(this.id);const cm=state.cm.get(this.id),course=state.course;this._refreshCompletion({state:state,element:cm}),window.location.href!=cm.url&&window.location.href!="".concat(course.baseurl,"#").concat(cm.anchor)||(this.reactive.dispatch("setPageItem","cm",this.id),this.element.scrollIntoView({block:"center"})),_config.default.contextid!=_config.default.courseContextId&&_config.default.contextInstanceId==this.id&&(this.reactive.dispatch("setPageItem","cm",this.id,!0),this.element.scrollIntoView({block:"center"})),cm.uservisible||this.addEventListener(this.getElement(this.selectors.CM_NAME),"click",this._activityAnchor)}getWatchers(){return[{watch:"cm[".concat(this.id,"]:deleted"),handler:this.remove},{watch:"cm[".concat(this.id,"]:updated"),handler:this._refreshCm},{watch:"cm[".concat(this.id,"].completionstate:updated"),handler:this._refreshCompletion},{watch:"course.pageItem:updated",handler:this._refreshPageItem}]}_refreshCm(_ref){var _element$dragging,_element$locked,_element$hascmrestric;let{element:element}=_ref;this.element.classList.toggle(this.classes.CMHIDDEN,!element.visible),this.getElement(this.selectors.CM_NAME).innerHTML=element.name,this.element.classList.toggle(this.classes.DRAGGING,null!==(_element$dragging=element.dragging)&&void 0!==_element$dragging&&_element$dragging),this.element.classList.toggle(this.classes.LOCKED,null!==(_element$locked=element.locked)&&void 0!==_element$locked&&_element$locked),this.element.classList.toggle(this.classes.RESTRICTIONS,null!==(_element$hascmrestric=element.hascmrestrictions)&&void 0!==_element$hascmrestric&&_element$hascmrestric),this.locked=element.locked}_refreshPageItem(_ref2){let{element:element}=_ref2;if(!element.pageItem)return;const isPageId="cm"==element.pageItem.type&&element.pageItem.id==this.id;this.element.classList.toggle(this.classes.PAGEITEM,isPageId),isPageId&&!this.reactive.isEditing&&this.element.scrollIntoView({block:"nearest"})}async _refreshCompletion(_ref3){let{state:state,element:element}=_ref3;if(this.reactive.isEditing||!element.istrackeduser)return;const completionElement=this.getElement(this.selectors.CM_COMPLETION);if(completionElement.dataset.value==element.completionstate)return;const data=this.reactive.getExporter().cmCompletion(state,element);try{const{html:html,js:js}=await _templates.default.renderForPromise("core_courseformat/local/courseindex/cmcompletion",data);_templates.default.replaceNode(completionElement,html,js)}catch(error){throw error}}_activityAnchor(event){const cm=this.reactive.get("cm",this.id);if(document.getElementById(cm.anchor))return void setTimeout((()=>{this.reactive.dispatch("setPageItem","cm",cm.id)}),50);const course=this.reactive.get("course"),section=this.reactive.get("section",cm.sectionid);if(!section)return;const url="".concat(course.baseurl,"&section=").concat(section.number,"#").concat(cm.anchor);event.preventDefault(),window.location=url}}return _exports.default=Component,_exports.default}));
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_dndcmitem=_interopRequireDefault(_dndcmitem),_templates=_interopRequireDefault(_templates),_prefetch=_interopRequireDefault(_prefetch),_config=_interopRequireDefault(_config);_prefetch.default.prefetchTemplate("core_courseformat/local/courseindex/cmcompletion");class Component extends _dndcmitem.default{create(){this.name="courseindex_cm",this.selectors={CM_NAME:"[data-for='cm_name']",CM_COMPLETION:"[data-for='cm_completion']"},this.classes={CMHIDDEN:"dimmed",LOCKED:"editinprogress",RESTRICTIONS:"restrictions",PAGEITEM:"pageitem"},this.id=this.element.dataset.id}static init(target,selectors){return new this({element:document.getElementById(target),selectors:selectors})}stateReady(state){this.configDragDrop(this.id);const cm=state.cm.get(this.id),course=state.course;this._refreshCompletion({state:state,element:cm}),window.location.href!=cm.url&&window.location.href!="".concat(course.baseurl,"#").concat(cm.anchor)||(this.reactive.dispatch("setPageItem","cm",this.id),this.element.scrollIntoView({block:"center"})),_config.default.contextid!=_config.default.courseContextId&&_config.default.contextInstanceId==this.id&&(this.reactive.dispatch("setPageItem","cm",this.id,!0),this.element.scrollIntoView({block:"center"})),cm.uservisible||this.addEventListener(this.getElement(this.selectors.CM_NAME),"click",this._activityAnchor)}getWatchers(){return[{watch:"cm[".concat(this.id,"]:deleted"),handler:this.remove},{watch:"cm[".concat(this.id,"]:updated"),handler:this._refreshCm},{watch:"cm[".concat(this.id,"].completionstate:updated"),handler:this._refreshCompletion},{watch:"course.pageItem:updated",handler:this._refreshPageItem}]}_refreshCm(_ref){var _element$dragging,_element$locked,_element$hascmrestric;let{element:element}=_ref;this.element.classList.toggle(this.classes.CMHIDDEN,!element.visible),this.getElement(this.selectors.CM_NAME).innerHTML=element.name,this.element.classList.toggle(this.classes.DRAGGING,null!==(_element$dragging=element.dragging)&&void 0!==_element$dragging&&_element$dragging),this.element.classList.toggle(this.classes.LOCKED,null!==(_element$locked=element.locked)&&void 0!==_element$locked&&_element$locked),this.element.classList.toggle(this.classes.RESTRICTIONS,null!==(_element$hascmrestric=element.hascmrestrictions)&&void 0!==_element$hascmrestric&&_element$hascmrestric),this.locked=element.locked}_refreshPageItem(_ref2){let{element:element}=_ref2;if(!element.pageItem)return;const isPageId="cm"==element.pageItem.type&&element.pageItem.id==this.id;this.element.classList.toggle(this.classes.PAGEITEM,isPageId),isPageId&&!this.reactive.isEditing&&this.element.scrollIntoView({block:"nearest"})}async _refreshCompletion(_ref3){let{state:state,element:element}=_ref3;if(this.reactive.isEditing||!element.istrackeduser)return;const completionElement=this.getElement(this.selectors.CM_COMPLETION);if(completionElement.dataset.value==element.completionstate)return;const data=this.reactive.getExporter().cmCompletion(state,element);try{const{html:html,js:js}=await _templates.default.renderForPromise("core_courseformat/local/courseindex/cmcompletion",data);_templates.default.replaceNode(completionElement,html,js)}catch(error){throw error}}_activityAnchor(event){const cm=this.reactive.get("cm",this.id);if(document.getElementById(cm.anchor))return void setTimeout((()=>{this.reactive.dispatch("setPageItem","cm",cm.id)}),50);const course=this.reactive.get("course"),section=this.reactive.get("section",cm.sectionid);if(!section)return;const url="".concat(course.baseurl,"&section=").concat(section.number,"#").concat(cm.anchor);event.preventDefault(),window.location=url}}return _exports.default=Component,_exports.default}));
//# sourceMappingURL=cm.min.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -10,6 +10,6 @@ define("core_courseformat/local/courseindex/drawer",["exports","core/reactive","
* @copyright 2021 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class Component extends _reactive.BaseComponent{create(){this.name="courseindex-drawer"}static init(target,selectors){return new Component({element:document.getElementById(target),reactive:(0,_courseeditor.getCurrentCourseEditor)(),selectors:selectors})}}return _exports.default=Component,_exports.default}));
class Component extends _reactive.BaseComponent{create(){this.name="courseindex-drawer"}static init(target,selectors){return new this({element:document.getElementById(target),reactive:(0,_courseeditor.getCurrentCourseEditor)(),selectors:selectors})}}return _exports.default=Component,_exports.default}));
//# sourceMappingURL=drawer.min.js.map
@@ -1 +1 @@
{"version":3,"file":"drawer.min.js","sources":["../../../src/local/courseindex/drawer.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Course index drawer wrap.\n *\n * This component is mostly used to ensure all subcomponents find a parent\n * compoment with a reactive instance defined.\n *\n * @module core_courseformat/local/courseindex/drawer\n * @class core_courseformat/local/courseindex/drawer\n * @copyright 2021 Ferran Recio <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'courseindex-drawer';\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new Component({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n}\n"],"names":["Component","BaseComponent","create","name","target","selectors","element","document","getElementById","reactive"],"mappings":";;;;;;;;;;;;MA8BqBA,kBAAkBC,wBAKnCC,cAESC,KAAO,iCAUJC,OAAQC,kBACT,IAAIL,UAAU,CACjBM,QAASC,SAASC,eAAeJ,QACjCK,UAAU,0CACVJ,UAAAA"}
{"version":3,"file":"drawer.min.js","sources":["../../../src/local/courseindex/drawer.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Course index drawer wrap.\n *\n * This component is mostly used to ensure all subcomponents find a parent\n * compoment with a reactive instance defined.\n *\n * @module core_courseformat/local/courseindex/drawer\n * @class core_courseformat/local/courseindex/drawer\n * @copyright 2021 Ferran Recio <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'courseindex-drawer';\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n}\n"],"names":["Component","BaseComponent","create","name","target","selectors","this","element","document","getElementById","reactive"],"mappings":";;;;;;;;;;;;MA8BqBA,kBAAkBC,wBAKnCC,cAESC,KAAO,iCAUJC,OAAQC,kBACT,IAAIC,KAAK,CACZC,QAASC,SAASC,eAAeL,QACjCM,UAAU,0CACVL,UAAAA"}
@@ -6,6 +6,6 @@ define("core_courseformat/local/courseindex/placeholder",["exports","core/reacti
* @class core_courseformat/local/courseindex/placeholder
* @copyright 2021 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending);class Component extends _reactive.BaseComponent{static init(target,selectors){return new Component({element:document.getElementById(target),reactive:(0,_courseeditor.getCurrentCourseEditor)(),selectors:selectors})}create(){this.pendingContent=new _pending.default("core_courseformat/placeholder:loadcourseindex")}async stateReady(state){this.loadStaticContent()||await this.loadTemplateContent(state)}loadStaticContent(){const index=this.reactive.getStorageValue("courseIndex");return!(!index.html||!index.js)&&(_templates.default.replaceNode(this.element,index.html,index.js),this.pendingContent.resolve(),!0)}async loadTemplateContent(state){const data=this.reactive.getExporter().course(state);try{const{html:html,js:js}=await _templates.default.renderForPromise("core_courseformat/local/courseindex/courseindex",data);_templates.default.replaceNode(this.element,html,js),this.pendingContent.resolve(),this.reactive.setStorageValue("courseIndex",{html:html,js:js})}catch(error){throw this.pendingContent.resolve(error),error}}}return _exports.default=Component,_exports.default}));
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending);class Component extends _reactive.BaseComponent{static init(target,selectors){return new this({element:document.getElementById(target),reactive:(0,_courseeditor.getCurrentCourseEditor)(),selectors:selectors})}create(){this.pendingContent=new _pending.default("core_courseformat/placeholder:loadcourseindex")}async stateReady(state){this.loadStaticContent()||await this.loadTemplateContent(state)}loadStaticContent(){const index=this.reactive.getStorageValue("courseIndex");return!(!index.html||!index.js)&&(_templates.default.replaceNode(this.element,index.html,index.js),this.pendingContent.resolve(),!0)}async loadTemplateContent(state){const data=this.reactive.getExporter().course(state);try{const{html:html,js:js}=await _templates.default.renderForPromise("core_courseformat/local/courseindex/courseindex",data);_templates.default.replaceNode(this.element,html,js),this.pendingContent.resolve(),this.reactive.setStorageValue("courseIndex",{html:html,js:js})}catch(error){throw this.pendingContent.resolve(error),error}}}return _exports.default=Component,_exports.default}));
//# sourceMappingURL=placeholder.min.js.map
@@ -1 +1 @@
{"version":3,"file":"placeholder.min.js","sources":["../../../src/local/courseindex/placeholder.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Course index placeholder replacer.\n *\n * @module core_courseformat/local/courseindex/placeholder\n * @class core_courseformat/local/courseindex/placeholder\n * @copyright 2021 Ferran Recio <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport Templates from 'core/templates';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport Pending from 'core/pending';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new Component({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n\n /**\n * Component creation hook.\n */\n create() {\n // Add a pending operation waiting for the initial content.\n this.pendingContent = new Pending(`core_courseformat/placeholder:loadcourseindex`);\n }\n\n /**\n * Initial state ready method.\n *\n * This stateReady to be async because it loads the real courseindex.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n\n // Check if we have a static course index already loded from a previous page.\n if (!this.loadStaticContent()) {\n await this.loadTemplateContent(state);\n }\n }\n\n /**\n * Load the course index from the session storage if any.\n *\n * @return {boolean} true if the static version is loaded form the session\n */\n loadStaticContent() {\n // Load the previous static course index from the session cache.\n const index = this.reactive.getStorageValue(`courseIndex`);\n if (index.html && index.js) {\n Templates.replaceNode(this.element, index.html, index.js);\n this.pendingContent.resolve();\n return true;\n }\n return false;\n }\n\n /**\n * Load the course index template.\n *\n * @param {Object} state the initial state\n */\n async loadTemplateContent(state) {\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(state);\n try {\n // To render an HTML into our component we just use the regular Templates module.\n const {html, js} = await Templates.renderForPromise(\n 'core_courseformat/local/courseindex/courseindex',\n data,\n );\n Templates.replaceNode(this.element, html, js);\n this.pendingContent.resolve();\n\n // Save the rendered template into the session cache.\n this.reactive.setStorageValue(`courseIndex`, {html, js});\n } catch (error) {\n this.pendingContent.resolve(error);\n throw error;\n }\n }\n}\n"],"names":["Component","BaseComponent","target","selectors","element","document","getElementById","reactive","create","pendingContent","Pending","state","this","loadStaticContent","loadTemplateContent","index","getStorageValue","html","js","replaceNode","resolve","data","getExporter","course","Templates","renderForPromise","setStorageValue","error"],"mappings":";;;;;;;;mLA6BqBA,kBAAkBC,oCASvBC,OAAQC,kBACT,IAAIH,UAAU,CACjBI,QAASC,SAASC,eAAeJ,QACjCK,UAAU,0CACVJ,UAAAA,YAORK,cAESC,eAAiB,IAAIC,mFAUbC,OAGRC,KAAKC,2BACAD,KAAKE,oBAAoBH,OASvCE,0BAEUE,MAAQH,KAAKL,SAASS,wCACxBD,MAAME,OAAQF,MAAMG,yBACVC,YAAYP,KAAKR,QAASW,MAAME,KAAMF,MAAMG,SACjDT,eAAeW,WACb,6BAUWT,aAGhBU,KADWT,KAAKL,SAASe,cACTC,OAAOZ,iBAGnBM,KAACA,KAADC,GAAOA,UAAYM,mBAAUC,iBAC/B,kDACAJ,yBAEMF,YAAYP,KAAKR,QAASa,KAAMC,SACrCT,eAAeW,eAGfb,SAASmB,8BAA+B,CAACT,KAAAA,KAAMC,GAAAA,KACtD,MAAOS,kBACAlB,eAAeW,QAAQO,OACtBA"}
{"version":3,"file":"placeholder.min.js","sources":["../../../src/local/courseindex/placeholder.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Course index placeholder replacer.\n *\n * @module core_courseformat/local/courseindex/placeholder\n * @class core_courseformat/local/courseindex/placeholder\n * @copyright 2021 Ferran Recio <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport Templates from 'core/templates';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport Pending from 'core/pending';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n\n /**\n * Component creation hook.\n */\n create() {\n // Add a pending operation waiting for the initial content.\n this.pendingContent = new Pending(`core_courseformat/placeholder:loadcourseindex`);\n }\n\n /**\n * Initial state ready method.\n *\n * This stateReady to be async because it loads the real courseindex.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n\n // Check if we have a static course index already loded from a previous page.\n if (!this.loadStaticContent()) {\n await this.loadTemplateContent(state);\n }\n }\n\n /**\n * Load the course index from the session storage if any.\n *\n * @return {boolean} true if the static version is loaded form the session\n */\n loadStaticContent() {\n // Load the previous static course index from the session cache.\n const index = this.reactive.getStorageValue(`courseIndex`);\n if (index.html && index.js) {\n Templates.replaceNode(this.element, index.html, index.js);\n this.pendingContent.resolve();\n return true;\n }\n return false;\n }\n\n /**\n * Load the course index template.\n *\n * @param {Object} state the initial state\n */\n async loadTemplateContent(state) {\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.course(state);\n try {\n // To render an HTML into our component we just use the regular Templates module.\n const {html, js} = await Templates.renderForPromise(\n 'core_courseformat/local/courseindex/courseindex',\n data,\n );\n Templates.replaceNode(this.element, html, js);\n this.pendingContent.resolve();\n\n // Save the rendered template into the session cache.\n this.reactive.setStorageValue(`courseIndex`, {html, js});\n } catch (error) {\n this.pendingContent.resolve(error);\n throw error;\n }\n }\n}\n"],"names":["Component","BaseComponent","target","selectors","this","element","document","getElementById","reactive","create","pendingContent","Pending","state","loadStaticContent","loadTemplateContent","index","getStorageValue","html","js","replaceNode","resolve","data","getExporter","course","Templates","renderForPromise","setStorageValue","error"],"mappings":";;;;;;;;mLA6BqBA,kBAAkBC,oCASvBC,OAAQC,kBACT,IAAIC,KAAK,CACZC,QAASC,SAASC,eAAeL,QACjCM,UAAU,0CACVL,UAAAA,YAORM,cAESC,eAAiB,IAAIC,mFAUbC,OAGRR,KAAKS,2BACAT,KAAKU,oBAAoBF,OASvCC,0BAEUE,MAAQX,KAAKI,SAASQ,wCACxBD,MAAME,OAAQF,MAAMG,yBACVC,YAAYf,KAAKC,QAASU,MAAME,KAAMF,MAAMG,SACjDR,eAAeU,WACb,6BAUWR,aAGhBS,KADWjB,KAAKI,SAASc,cACTC,OAAOX,iBAGnBK,KAACA,KAADC,GAAOA,UAAYM,mBAAUC,iBAC/B,kDACAJ,yBAEMF,YAAYf,KAAKC,QAASY,KAAMC,SACrCR,eAAeU,eAGfZ,SAASkB,8BAA+B,CAACT,KAAAA,KAAMC,GAAAA,KACtD,MAAOS,kBACAjB,eAAeU,QAAQO,OACtBA"}
+1 -1
View File
@@ -8,6 +8,6 @@ define("core_courseformat/local/courseindex/section",["exports","core_courseform
* @class core_courseformat/local/courseindex/section
* @copyright 2021 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_sectiontitle=_interopRequireDefault(_sectiontitle),_dndsection=_interopRequireDefault(_dndsection);class Component extends _dndsection.default{create(){this.name="courseindex_section",this.selectors={SECTION_ITEM:"[data-for='section_item']",SECTION_TITLE:"[data-for='section_title']",CM_LAST:'[data-for="cm"]:last-child'},this.classes={SECTIONHIDDEN:"dimmed",SECTIONCURRENT:"current",LOCKED:"editinprogress",RESTRICTIONS:"restrictions",PAGEITEM:"pageitem"},this.id=this.element.dataset.id,this.isPageItem=!1}static init(target,selectors){return new Component({element:document.getElementById(target),selectors:selectors})}stateReady(state){this.configState(state);const sectionItem=this.getElement(this.selectors.SECTION_ITEM);if(this.reactive.isEditing&&this.reactive.supportComponents){const titleitem=new _sectiontitle.default({...this,element:sectionItem,fullregion:this.element});this.configDragDrop(titleitem)}const section=state.section.get(this.id);window.location.href==section.sectionurl.replace(/&amp;/g,"&")&&(this.reactive.dispatch("setPageItem","section",this.id),sectionItem.scrollIntoView())}getWatchers(){return[{watch:"section[".concat(this.id,"]:deleted"),handler:this.remove},{watch:"section[".concat(this.id,"]:updated"),handler:this._refreshSection},{watch:"course.pageItem:updated",handler:this._refreshPageItem}]}getLastCm(){return this.getElement(this.selectors.CM_LAST)}_refreshSection(_ref){var _element$hasrestricti,_element$dragging,_element$locked;let{element:element}=_ref;const sectionItem=this.getElement(this.selectors.SECTION_ITEM);sectionItem.classList.toggle(this.classes.SECTIONHIDDEN,!element.visible),sectionItem.classList.toggle(this.classes.RESTRICTIONS,null!==(_element$hasrestricti=element.hasrestrictions)&&void 0!==_element$hasrestricti&&_element$hasrestricti),this.element.classList.toggle(this.classes.SECTIONCURRENT,element.current),this.element.classList.toggle(this.classes.DRAGGING,null!==(_element$dragging=element.dragging)&&void 0!==_element$dragging&&_element$dragging),this.element.classList.toggle(this.classes.LOCKED,null!==(_element$locked=element.locked)&&void 0!==_element$locked&&_element$locked),this.locked=element.locked,this.getElement(this.selectors.SECTION_TITLE).innerHTML=element.title}_refreshPageItem(_ref2){var _element$pageItem,_this$pageItem;let{element:element,state:state}=_ref2;if(!element.pageItem)return;if(element.pageItem.sectionId!==this.id&&this.isPageItem)return this.pageItem=!1,void this.getElement(this.selectors.SECTION_ITEM).classList.remove(this.classes.PAGEITEM);var _element$pageItem2;!state.section.get(this.id).indexcollapsed||null!==(_element$pageItem=element.pageItem)&&void 0!==_element$pageItem&&_element$pageItem.isStatic?this.pageItem="section"==element.pageItem.type&&element.pageItem.id==this.id:this.pageItem=(null===(_element$pageItem2=element.pageItem)||void 0===_element$pageItem2?void 0:_element$pageItem2.sectionId)==this.id;this.getElement(this.selectors.SECTION_ITEM).classList.toggle(this.classes.PAGEITEM,null!==(_this$pageItem=this.pageItem)&&void 0!==_this$pageItem&&_this$pageItem),this.pageItem&&!this.reactive.isEditing&&this.element.scrollIntoView({block:"nearest"})}}return _exports.default=Component,_exports.default}));
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_sectiontitle=_interopRequireDefault(_sectiontitle),_dndsection=_interopRequireDefault(_dndsection);class Component extends _dndsection.default{create(){this.name="courseindex_section",this.selectors={SECTION_ITEM:"[data-for='section_item']",SECTION_TITLE:"[data-for='section_title']",CM_LAST:'[data-for="cm"]:last-child'},this.classes={SECTIONHIDDEN:"dimmed",SECTIONCURRENT:"current",LOCKED:"editinprogress",RESTRICTIONS:"restrictions",PAGEITEM:"pageitem"},this.id=this.element.dataset.id,this.isPageItem=!1}static init(target,selectors){return new this({element:document.getElementById(target),selectors:selectors})}stateReady(state){this.configState(state);const sectionItem=this.getElement(this.selectors.SECTION_ITEM);if(this.reactive.isEditing&&this.reactive.supportComponents){const titleitem=new _sectiontitle.default({...this,element:sectionItem,fullregion:this.element});this.configDragDrop(titleitem)}const section=state.section.get(this.id);window.location.href==section.sectionurl.replace(/&amp;/g,"&")&&(this.reactive.dispatch("setPageItem","section",this.id),sectionItem.scrollIntoView())}getWatchers(){return[{watch:"section[".concat(this.id,"]:deleted"),handler:this.remove},{watch:"section[".concat(this.id,"]:updated"),handler:this._refreshSection},{watch:"course.pageItem:updated",handler:this._refreshPageItem}]}getLastCm(){return this.getElement(this.selectors.CM_LAST)}_refreshSection(_ref){var _element$hasrestricti,_element$dragging,_element$locked;let{element:element}=_ref;const sectionItem=this.getElement(this.selectors.SECTION_ITEM);sectionItem.classList.toggle(this.classes.SECTIONHIDDEN,!element.visible),sectionItem.classList.toggle(this.classes.RESTRICTIONS,null!==(_element$hasrestricti=element.hasrestrictions)&&void 0!==_element$hasrestricti&&_element$hasrestricti),this.element.classList.toggle(this.classes.SECTIONCURRENT,element.current),this.element.classList.toggle(this.classes.DRAGGING,null!==(_element$dragging=element.dragging)&&void 0!==_element$dragging&&_element$dragging),this.element.classList.toggle(this.classes.LOCKED,null!==(_element$locked=element.locked)&&void 0!==_element$locked&&_element$locked),this.locked=element.locked,this.getElement(this.selectors.SECTION_TITLE).innerHTML=element.title}_refreshPageItem(_ref2){var _element$pageItem,_this$pageItem;let{element:element,state:state}=_ref2;if(!element.pageItem)return;if(element.pageItem.sectionId!==this.id&&this.isPageItem)return this.pageItem=!1,void this.getElement(this.selectors.SECTION_ITEM).classList.remove(this.classes.PAGEITEM);var _element$pageItem2;!state.section.get(this.id).indexcollapsed||null!==(_element$pageItem=element.pageItem)&&void 0!==_element$pageItem&&_element$pageItem.isStatic?this.pageItem="section"==element.pageItem.type&&element.pageItem.id==this.id:this.pageItem=(null===(_element$pageItem2=element.pageItem)||void 0===_element$pageItem2?void 0:_element$pageItem2.sectionId)==this.id;this.getElement(this.selectors.SECTION_ITEM).classList.toggle(this.classes.PAGEITEM,null!==(_this$pageItem=this.pageItem)&&void 0!==_this$pageItem&&_this$pageItem),this.pageItem&&!this.reactive.isEditing&&this.element.scrollIntoView({block:"nearest"})}}return _exports.default=Component,_exports.default}));
//# sourceMappingURL=section.min.js.map
File diff suppressed because one or more lines are too long
@@ -8,6 +8,6 @@ define("core_courseformat/local/courseindex/sectiontitle",["exports","core_cours
* @class core_courseformat/local/courseindex/sectiontitle
* @copyright 2021 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_dndsectionitem=(obj=_dndsectionitem)&&obj.__esModule?obj:{default:obj};class Component extends _dndsectionitem.default{create(descriptor){this.name="courseindex_sectiontitle",this.id=descriptor.id,this.section=descriptor.section,this.course=descriptor.course,this.fullregion=descriptor.fullregion,this.section.number>0&&(this.getDraggableData=this._getDraggableData)}static init(target,selectors){return new Component({element:document.getElementById(target),selectors:selectors})}stateReady(state){this.configDragDrop(this.id,state,this.fullregion)}}return _exports.default=Component,_exports.default}));
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_dndsectionitem=(obj=_dndsectionitem)&&obj.__esModule?obj:{default:obj};class Component extends _dndsectionitem.default{create(descriptor){this.name="courseindex_sectiontitle",this.id=descriptor.id,this.section=descriptor.section,this.course=descriptor.course,this.fullregion=descriptor.fullregion,this.section.number>0&&(this.getDraggableData=this._getDraggableData)}static init(target,selectors){return new this({element:document.getElementById(target),selectors:selectors})}stateReady(state){this.configDragDrop(this.id,state,this.fullregion)}}return _exports.default=Component,_exports.default}));
//# sourceMappingURL=sectiontitle.min.js.map
@@ -1 +1 @@
{"version":3,"file":"sectiontitle.min.js","sources":["../../../src/local/courseindex/sectiontitle.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Course index section title component.\n *\n * This component is used to control specific course section interactions like drag and drop.\n *\n * @module core_courseformat/local/courseindex/sectiontitle\n * @class core_courseformat/local/courseindex/sectiontitle\n * @copyright 2021 Ferran Recio <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport DndSectionItem from 'core_courseformat/local/courseeditor/dndsectionitem';\n\nexport default class Component extends DndSectionItem {\n\n /**\n * Constructor hook.\n *\n * @param {Object} descriptor\n */\n create(descriptor) {\n // Optional component name for debugging.\n this.name = 'courseindex_sectiontitle';\n\n this.id = descriptor.id;\n this.section = descriptor.section;\n this.course = descriptor.course;\n this.fullregion = descriptor.fullregion;\n\n // Prevent topic zero from being draggable.\n if (this.section.number > 0) {\n this.getDraggableData = this._getDraggableData;\n }\n }\n\n /**\n * Static method to create a component instance form the mustahce template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new Component({\n element: document.getElementById(target),\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the initial state\n */\n stateReady(state) {\n this.configDragDrop(this.id, state, this.fullregion);\n }\n}\n"],"names":["Component","DndSectionItem","create","descriptor","name","id","section","course","fullregion","this","number","getDraggableData","_getDraggableData","target","selectors","element","document","getElementById","stateReady","state","configDragDrop"],"mappings":";;;;;;;;;;mKA4BqBA,kBAAkBC,wBAOnCC,OAAOC,iBAEEC,KAAO,gCAEPC,GAAKF,WAAWE,QAChBC,QAAUH,WAAWG,aACrBC,OAASJ,WAAWI,YACpBC,WAAaL,WAAWK,WAGzBC,KAAKH,QAAQI,OAAS,SACjBC,iBAAmBF,KAAKG,+BAWzBC,OAAQC,kBACT,IAAId,UAAU,CACjBe,QAASC,SAASC,eAAeJ,QACjCC,UAAAA,YASRI,WAAWC,YACFC,eAAeX,KAAKJ,GAAIc,MAAOV,KAAKD"}
{"version":3,"file":"sectiontitle.min.js","sources":["../../../src/local/courseindex/sectiontitle.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Course index section title component.\n *\n * This component is used to control specific course section interactions like drag and drop.\n *\n * @module core_courseformat/local/courseindex/sectiontitle\n * @class core_courseformat/local/courseindex/sectiontitle\n * @copyright 2021 Ferran Recio <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport DndSectionItem from 'core_courseformat/local/courseeditor/dndsectionitem';\n\nexport default class Component extends DndSectionItem {\n\n /**\n * Constructor hook.\n *\n * @param {Object} descriptor\n */\n create(descriptor) {\n // Optional component name for debugging.\n this.name = 'courseindex_sectiontitle';\n\n this.id = descriptor.id;\n this.section = descriptor.section;\n this.course = descriptor.course;\n this.fullregion = descriptor.fullregion;\n\n // Prevent topic zero from being draggable.\n if (this.section.number > 0) {\n this.getDraggableData = this._getDraggableData;\n }\n }\n\n /**\n * Static method to create a component instance form the mustahce template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.getElementById(target),\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the initial state\n */\n stateReady(state) {\n this.configDragDrop(this.id, state, this.fullregion);\n }\n}\n"],"names":["Component","DndSectionItem","create","descriptor","name","id","section","course","fullregion","this","number","getDraggableData","_getDraggableData","target","selectors","element","document","getElementById","stateReady","state","configDragDrop"],"mappings":";;;;;;;;;;mKA4BqBA,kBAAkBC,wBAOnCC,OAAOC,iBAEEC,KAAO,gCAEPC,GAAKF,WAAWE,QAChBC,QAAUH,WAAWG,aACrBC,OAASJ,WAAWI,YACpBC,WAAaL,WAAWK,WAGzBC,KAAKH,QAAQI,OAAS,SACjBC,iBAAmBF,KAAKG,+BAWzBC,OAAQC,kBACT,IAAIL,KAAK,CACZM,QAASC,SAASC,eAAeJ,QACjCC,UAAAA,YASRI,WAAWC,YACFC,eAAeX,KAAKJ,GAAIc,MAAOV,KAAKD"}
@@ -408,6 +408,50 @@ export default class extends BaseComponent {
this.reactive.dispatch(mutationName, [target.dataset.id]);
}
/**
* Handle a delete cm request.
*
* @param {Element} target the dispatch action element
* @param {Event} event the triggered event
*/
async _requestCmDelete(target, event) {
// Check we have an id.
const cmId = target.dataset.id;
if (!cmId) {
return;
}
const cmInfo = this.reactive.get('cm', cmId);
event.preventDefault();
const modalParams = {
title: getString('confirm', 'core'),
body: getString(
'deletechecktypename',
'moodle',
{
type: cmInfo.modname,
name: cmInfo.name,
}
),
saveButtonText: getString('delete', 'core'),
type: ModalFactory.types.SAVE_CANCEL,
};
const modal = await this._modalBodyRenderedPromise(modalParams);
modal.getRoot().on(
ModalEvents.save,
e => {
// Stop the default save button behaviour which is to close the modal.
e.preventDefault();
modal.destroy();
this.reactive.dispatch('cmDelete', [cmId]);
}
);
}
/**
* Disable all add sections actions.
*
@@ -246,6 +246,19 @@ export default class {
stateManager.processUpdates(updates);
}
/**
* Delete cms.
* @param {StateManager} stateManager the current state manager
* @param {array} cmIds the list of section ids
*/
async cmDelete(stateManager, cmIds) {
const course = stateManager.get('course');
this.cmLock(stateManager, cmIds, true);
const updates = await this._callEditWebservice('cm_delete', course.id, cmIds);
this.cmLock(stateManager, cmIds, false);
stateManager.processUpdates(updates);
}
/**
* Mark or unmark course modules as dragging.
*
@@ -65,7 +65,7 @@ export default class Component extends DndCmItem {
* @return {Component}
*/
static init(target, selectors) {
return new Component({
return new this({
element: document.getElementById(target),
selectors,
});
@@ -65,7 +65,7 @@ export default class Component extends BaseComponent {
* @return {Component}
*/
static init(target, selectors) {
return new Component({
return new this({
element: document.getElementById(target),
reactive: getCurrentCourseEditor(),
selectors,
@@ -46,7 +46,7 @@ export default class Component extends BaseComponent {
* @return {Component}
*/
static init(target, selectors) {
return new Component({
return new this({
element: document.getElementById(target),
reactive: getCurrentCourseEditor(),
selectors,
@@ -37,7 +37,7 @@ export default class Component extends BaseComponent {
* @return {Component}
*/
static init(target, selectors) {
return new Component({
return new this({
element: document.getElementById(target),
reactive: getCurrentCourseEditor(),
selectors,
@@ -63,7 +63,7 @@ export default class Component extends DndSection {
* @return {Component}
*/
static init(target, selectors) {
return new Component({
return new this({
element: document.getElementById(target),
selectors,
});
@@ -56,7 +56,7 @@ export default class Component extends DndSectionItem {
* @return {Component}
*/
static init(target, selectors) {
return new Component({
return new this({
element: document.getElementById(target),
selectors,
});
+14
View File
@@ -26,6 +26,7 @@ namespace core_courseformat;
use navigation_node;
use moodle_page;
use cm_info;
use core_component;
use course_modinfo;
use html_writer;
@@ -1473,6 +1474,19 @@ abstract class base {
return true;
}
/**
* Wrapper for course_delete_module method.
*
* Format plugins can override this method to provide their own implementation of course_delete_module.
*
* @param cm_info $cm the course module information
* @param bool $async whether or not to try to delete the module using an adhoc task. Async also depends on a plugin hook.
* @throws moodle_exception
*/
public function delete_module(cm_info $cm, bool $async = false) {
course_delete_module($cm->id, $async);
}
/**
* Prepares the templateable object to display section name
*
@@ -90,6 +90,7 @@ class cm implements renderable {
'sectionnumber' => $section->section,
'uservisible' => $cm->uservisible,
'hascmrestrictions' => $this->get_has_restrictions(),
'modname' => get_string('pluginname', 'mod_' . $cm->modname),
];
// Check the user access type to this cm.
+42
View File
@@ -422,6 +422,48 @@ class stateactions {
}
}
/**
* Delete course cms.
*
* @param stateupdates $updates the affected course elements track
* @param stdClass $course the course object
* @param int[] $ids section ids
* @param int $targetsectionid not used
* @param int $targetcmid not used
*/
public function cm_delete(
stateupdates $updates,
stdClass $course,
array $ids = [],
?int $targetsectionid = null,
?int $targetcmid = null
): void {
$this->validate_cms($course, $ids, __FUNCTION__);
// Check capabilities on every activity context.
foreach ($ids as $cmid) {
$modcontext = context_module::instance($cmid);
require_capability('moodle/course:manageactivities', $modcontext);
}
$format = course_get_format($course->id);
$modinfo = get_fast_modinfo($course);
$affectedsections = [];
$cms = $this->get_cm_info($modinfo, $ids);
foreach ($cms as $cm) {
$section = $cm->get_section_info();
$affectedsections[$section->id] = $section;
$format->delete_module($cm, true);
$updates->add_cm_remove($cm->id);
}
foreach ($affectedsections as $sectionid => $section) {
$updates->add_section_put($sectionid);
}
}
/**
* Extract several cm_info from the course_modinfo.
*
+72 -17
View File
@@ -594,21 +594,21 @@ class stateactions_test extends \advanced_testcase {
* @param string $role the user role
* @param string[] $idrefs the sections or cms id references to be used as method params
* @param bool $expectedexception whether the call should throw an exception
* @param int $expectedtotal the expected total number of state puts
* @param int[] $expectedtotal the expected total number of state indexed by put, remove and create
* @param string|null $coursefield the course field to check
* @param int|string|null $coursevalue the section field value
* @param string|null $sectionfield the section field to check
* @param int|string|null $sectionvalue the section field value
* @param string|null $cmfield the cm field to check
* @param int|string|null $cmvalue the cm field value
* @return array the state update summary
* @return array an array of elements to do extra validations (course, references, results)
*/
protected function basic_state_text(
string $method = 'section_hide',
string $role = 'editingteacher',
array $idrefs = [],
bool $expectedexception = false,
int $expectedtotal = 0,
array $expectedtotals = [],
?string $coursefield = null,
$coursevalue = 0,
?string $sectionfield = null,
@@ -632,6 +632,8 @@ class stateactions_test extends \advanced_testcase {
$references["cm1"] = $this->create_activity($course->id, 'book', 1, false);
$references["cm2"] = $this->create_activity($course->id, 'glossary', 2, true);
$references["cm3"] = $this->create_activity($course->id, 'page', 2, false);
$references["cm4"] = $this->create_activity($course->id, 'forum', 2, false);
$references["cm5"] = $this->create_activity($course->id, 'wiki', 2, false);
if ($expectedexception) {
$this->expectException(moodle_exception::class);
@@ -652,13 +654,10 @@ class stateactions_test extends \advanced_testcase {
// Format results in a way we can compare easily.
$results = $this->summarize_updates($updates);
// Most state actions does not use create or remove actions because they are designed
// to refresh parts of the state.
$this->assertEquals(0, $results['create']['count']);
$this->assertEquals(0, $results['remove']['count']);
// Validate we have all the expected entries.
$this->assertEquals($expectedtotal, $results['put']['count']);
$this->assertEquals($expectedtotals['create'] ?? 0, $results['create']['count']);
$this->assertEquals($expectedtotals['remove'] ?? 0, $results['remove']['count']);
$this->assertEquals($expectedtotals['put'] ?? 0, $results['put']['count']);
// Validate course, section and cm.
if (!empty($coursefield)) {
@@ -676,7 +675,11 @@ class stateactions_test extends \advanced_testcase {
$this->assertEquals($cmvalue, $cm->$cmfield);
}
}
return $results;
return [
'course' => $course,
'references' => $references,
'results' => $results,
];
}
/**
@@ -696,7 +699,7 @@ class stateactions_test extends \advanced_testcase {
$role,
['section1', 'section2', 'section3'],
$expectedexception,
7,
['put' => 9],
null,
null,
'visible',
@@ -723,7 +726,7 @@ class stateactions_test extends \advanced_testcase {
$role,
['section1', 'section2', 'section3'],
$expectedexception,
7,
['put' => 9],
null,
null,
'visible',
@@ -750,7 +753,7 @@ class stateactions_test extends \advanced_testcase {
$role,
['cm0', 'cm1', 'cm2', 'cm3'],
$expectedexception,
4,
['put' => 4],
null,
null,
null,
@@ -777,7 +780,7 @@ class stateactions_test extends \advanced_testcase {
$role,
['cm0', 'cm1', 'cm2', 'cm3'],
$expectedexception,
4,
['put' => 4],
null,
null,
null,
@@ -805,7 +808,7 @@ class stateactions_test extends \advanced_testcase {
$role,
['cm0', 'cm1', 'cm2', 'cm3'],
$expectedexception,
4,
['put' => 4],
null,
null,
null,
@@ -822,7 +825,7 @@ class stateactions_test extends \advanced_testcase {
$role,
['cm0', 'cm1'],
$expectedexception,
2,
['put' => 2],
null,
null,
null,
@@ -835,7 +838,7 @@ class stateactions_test extends \advanced_testcase {
$role,
['cm2', 'cm3'],
$expectedexception,
2,
['put' => 2],
null,
null,
null,
@@ -870,4 +873,56 @@ class stateactions_test extends \advanced_testcase {
],
];
}
/**
* Test for cm_delete
*
* @covers ::cm_delete
* @dataProvider basic_role_provider
* @param string $role the user role
* @param bool $expectedexception if it will expect an exception.
*/
public function test_cm_delete(
string $role = 'editingteacher',
bool $expectedexception = false
): void {
$this->resetAfterTest();
// We want modules to be deleted for good.
set_config('coursebinenable', 0, 'tool_recyclebin');
$info = $this->basic_state_text(
'cm_delete',
$role,
['cm2', 'cm3'],
$expectedexception,
['remove' => 2, 'put' => 1],
);
$course = $info['course'];
$references = $info['references'];
$results = $info['results'];
$courseformat = course_get_format($course->id);
$this->assertArrayNotHasKey($references['cm0'], $results['remove']['cm']);
$this->assertArrayNotHasKey($references['cm1'], $results['remove']['cm']);
$this->assertArrayHasKey($references['cm2'], $results['remove']['cm']);
$this->assertArrayHasKey($references['cm3'], $results['remove']['cm']);
$this->assertArrayNotHasKey($references['cm4'], $results['remove']['cm']);
$this->assertArrayNotHasKey($references['cm5'], $results['remove']['cm']);
// Check the new section cm list.
$newcmlist = $this->translate_references($references, ['cm4', 'cm5']);
$section = $results['put']['section'][$references['section2']];
$this->assertEquals($newcmlist, $section->cmlist);
// Check activities are deleted.
$modinfo = $courseformat->get_modinfo();
$cms = $modinfo->get_cms();
$this->assertArrayHasKey($references['cm0'], $cms);
$this->assertArrayHasKey($references['cm1'], $cms);
$this->assertArrayNotHasKey($references['cm2'], $cms);
$this->assertArrayNotHasKey($references['cm3'], $cms);
$this->assertArrayHasKey($references['cm4'], $cms);
$this->assertArrayHasKey($references['cm5'], $cms);
}
}
+2
View File
@@ -4,6 +4,8 @@ Overview of this plugin type at http://docs.moodle.org/dev/Course_formats
=== 4.2 ===
* New core_courseformat\base::get_context() to get the course context directly from the format instance.
* New core_courseformat\base::delete_module() method. Now format plugins can extend the activity deletion logic
by overriding this method.
=== 4.1 ===
* New \core_courseformat\stateupdates methods add_section_remove() and add_cm_remove() have been added to replace
+8 -3
View File
@@ -1836,10 +1836,15 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
// Delete.
if ($hasmanageactivities) {
$actions['delete'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('delete' => $mod->id)),
new pix_icon('t/delete', '', 'moodle', array('class' => 'iconsmall')),
new moodle_url($baseurl, ['delete' => $mod->id]),
new pix_icon('t/delete', '', 'moodle', ['class' => 'iconsmall']),
$str->delete,
array('class' => 'editing_delete', 'data-action' => 'delete', 'data-sectionreturn' => $sr)
[
'class' => 'editing_delete',
'data-action' => ($usecomponents) ? 'cmDelete' : 'delete',
'data-sectionreturn' => $sr,
'data-id' => $mod->id,
]
);
}
+1 -1
View File
@@ -1039,7 +1039,7 @@ class behat_course extends behat_base {
// JS modal windows and avoiding interacting them at the same time.
if ($this->running_javascript()) {
$this->execute('behat_general::i_click_on_in_the',
array(get_string('yes'), "button", "Confirm", "dialogue")
array(get_string('delete'), "button", "Confirm", "dialogue")
);
} else {
$this->execute("behat_forms::press_button", get_string('yes'));