diff --git a/course/format/amd/build/local/courseindex/cm.min.js b/course/format/amd/build/local/courseindex/cm.min.js index c5338e9409f..8fa2142fa8f 100644 --- a/course/format/amd/build/local/courseindex/cm.min.js +++ b/course/format/amd/build/local/courseindex/cm.min.js @@ -8,6 +8,6 @@ define("core_courseformat/local/courseindex/cm",["exports","core_courseformat/lo * @class core_courseformat/local/courseindex/cm * @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,_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",INDENTED:"indented"},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.element.classList.toggle(this.classes.INDENTED,element.indent),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,"§ion=").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",INDENTED:"indented"},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&&cm.url||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.element.classList.toggle(this.classes.INDENTED,element.indent),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,"§ion=").concat(section.number,"#").concat(cm.anchor);event.preventDefault(),window.location=url}}return _exports.default=Component,_exports.default})); //# sourceMappingURL=cm.min.js.map \ No newline at end of file diff --git a/course/format/amd/build/local/courseindex/cm.min.js.map b/course/format/amd/build/local/courseindex/cm.min.js.map index b87dfc60030..518b08fcd45 100644 --- a/course/format/amd/build/local/courseindex/cm.min.js.map +++ b/course/format/amd/build/local/courseindex/cm.min.js.map @@ -1 +1 @@ -{"version":3,"file":"cm.min.js","sources":["../../../src/local/courseindex/cm.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 index cm component.\n *\n * This component is used to control specific course modules interactions like drag and drop.\n *\n * @module core_courseformat/local/courseindex/cm\n * @class core_courseformat/local/courseindex/cm\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport DndCmItem from 'core_courseformat/local/courseeditor/dndcmitem';\nimport Templates from 'core/templates';\nimport Prefetch from 'core/prefetch';\nimport Config from 'core/config';\n\n// Prefetch the completion icons template.\nconst completionTemplate = 'core_courseformat/local/courseindex/cmcompletion';\nPrefetch.prefetchTemplate(completionTemplate);\n\nexport default class Component extends DndCmItem {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'courseindex_cm';\n // Default query selectors.\n this.selectors = {\n CM_NAME: `[data-for='cm_name']`,\n CM_COMPLETION: `[data-for='cm_completion']`,\n };\n // Default classes to toggle on refresh.\n this.classes = {\n CMHIDDEN: 'dimmed',\n LOCKED: 'editinprogress',\n RESTRICTIONS: 'restrictions',\n PAGEITEM: 'pageitem',\n INDENTED: 'indented',\n };\n // We need our id to watch specific events.\n this.id = this.element.dataset.id;\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 selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the course state.\n */\n stateReady(state) {\n this.configDragDrop(this.id);\n const cm = state.cm.get(this.id);\n const course = state.course;\n // Refresh completion icon.\n this._refreshCompletion({\n state,\n element: cm,\n });\n // Check if the current url is the cm url.\n if (window.location.href == cm.url || window.location.href == `${course.baseurl}#${cm.anchor}`) {\n this.reactive.dispatch('setPageItem', 'cm', this.id);\n this.element.scrollIntoView({block: \"center\"});\n }\n // Check if this we are displaying this activity page.\n if (Config.contextid != Config.courseContextId && Config.contextInstanceId == this.id) {\n this.reactive.dispatch('setPageItem', 'cm', this.id, true);\n this.element.scrollIntoView({block: \"center\"});\n }\n // Add anchor logic if the element is not user visible.\n if (!cm.uservisible) {\n this.addEventListener(\n this.getElement(this.selectors.CM_NAME),\n 'click',\n this._activityAnchor,\n );\n }\n }\n\n /**\n * Component watchers.\n *\n * @returns {Array} of watchers\n */\n getWatchers() {\n return [\n {watch: `cm[${this.id}]:deleted`, handler: this.remove},\n {watch: `cm[${this.id}]:updated`, handler: this._refreshCm},\n {watch: `cm[${this.id}].completionstate:updated`, handler: this._refreshCompletion},\n {watch: `course.pageItem:updated`, handler: this._refreshPageItem},\n ];\n }\n\n /**\n * Update a course index cm using the state information.\n *\n * @param {object} param\n * @param {Object} param.element details the update details.\n */\n _refreshCm({element}) {\n // Update classes.\n this.element.classList.toggle(this.classes.CMHIDDEN, !element.visible);\n this.getElement(this.selectors.CM_NAME).innerHTML = element.name;\n this.element.classList.toggle(this.classes.DRAGGING, element.dragging ?? false);\n this.element.classList.toggle(this.classes.LOCKED, element.locked ?? false);\n this.element.classList.toggle(this.classes.RESTRICTIONS, element.hascmrestrictions ?? false);\n this.element.classList.toggle(this.classes.INDENTED, element.indent);\n this.locked = element.locked;\n }\n\n /**\n * Handle a page item update.\n *\n * @param {Object} details the update details\n * @param {Object} details.element the course state data.\n */\n _refreshPageItem({element}) {\n if (!element.pageItem) {\n return;\n }\n const isPageId = (element.pageItem.type == 'cm' && element.pageItem.id == this.id);\n this.element.classList.toggle(this.classes.PAGEITEM, isPageId);\n if (isPageId && !this.reactive.isEditing) {\n this.element.scrollIntoView({block: \"nearest\"});\n }\n }\n\n /**\n * Update the activity completion icon.\n *\n * @param {Object} details the update details\n * @param {Object} details.state the state data\n * @param {Object} details.element the element data\n */\n async _refreshCompletion({state, element}) {\n // No completion icons are displayed in edit mode.\n if (this.reactive.isEditing || !element.istrackeduser) {\n return;\n }\n // Check if the completion value has changed.\n const completionElement = this.getElement(this.selectors.CM_COMPLETION);\n if (completionElement.dataset.value == element.completionstate) {\n return;\n }\n\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.cmCompletion(state, element);\n\n try {\n const {html, js} = await Templates.renderForPromise(completionTemplate, data);\n Templates.replaceNode(completionElement, html, js);\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * The activity anchor event.\n *\n * @param {Event} event\n */\n _activityAnchor(event) {\n const cm = this.reactive.get('cm', this.id);\n // If the user cannot access the element but the element is present in the page\n // the new url should be an anchor link.\n const element = document.getElementById(cm.anchor);\n if (element) {\n // Marc the element as page item once the event is handled.\n setTimeout(() => {\n this.reactive.dispatch('setPageItem', 'cm', cm.id);\n }, 50);\n return;\n }\n // If the element is not present in the page we need to go to the specific section.\n const course = this.reactive.get('course');\n const section = this.reactive.get('section', cm.sectionid);\n if (!section) {\n return;\n }\n const url = `${course.baseurl}§ion=${section.number}#${cm.anchor}`;\n event.preventDefault();\n window.location = url;\n }\n}\n"],"names":["prefetchTemplate","Component","DndCmItem","create","name","selectors","CM_NAME","CM_COMPLETION","classes","CMHIDDEN","LOCKED","RESTRICTIONS","PAGEITEM","INDENTED","id","this","element","dataset","target","document","getElementById","stateReady","state","configDragDrop","cm","get","course","_refreshCompletion","window","location","href","url","baseurl","anchor","reactive","dispatch","scrollIntoView","block","Config","contextid","courseContextId","contextInstanceId","uservisible","addEventListener","getElement","_activityAnchor","getWatchers","watch","handler","remove","_refreshCm","_refreshPageItem","classList","toggle","visible","innerHTML","DRAGGING","dragging","locked","hascmrestrictions","indent","pageItem","isPageId","type","isEditing","istrackeduser","completionElement","value","completionstate","data","getExporter","cmCompletion","html","js","Templates","renderForPromise","replaceNode","error","event","setTimeout","section","sectionid","number","preventDefault"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"cm.min.js","sources":["../../../src/local/courseindex/cm.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 index cm component.\n *\n * This component is used to control specific course modules interactions like drag and drop.\n *\n * @module core_courseformat/local/courseindex/cm\n * @class core_courseformat/local/courseindex/cm\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport DndCmItem from 'core_courseformat/local/courseeditor/dndcmitem';\nimport Templates from 'core/templates';\nimport Prefetch from 'core/prefetch';\nimport Config from 'core/config';\n\n// Prefetch the completion icons template.\nconst completionTemplate = 'core_courseformat/local/courseindex/cmcompletion';\nPrefetch.prefetchTemplate(completionTemplate);\n\nexport default class Component extends DndCmItem {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'courseindex_cm';\n // Default query selectors.\n this.selectors = {\n CM_NAME: `[data-for='cm_name']`,\n CM_COMPLETION: `[data-for='cm_completion']`,\n };\n // Default classes to toggle on refresh.\n this.classes = {\n CMHIDDEN: 'dimmed',\n LOCKED: 'editinprogress',\n RESTRICTIONS: 'restrictions',\n PAGEITEM: 'pageitem',\n INDENTED: 'indented',\n };\n // We need our id to watch specific events.\n this.id = this.element.dataset.id;\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 selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the course state.\n */\n stateReady(state) {\n this.configDragDrop(this.id);\n const cm = state.cm.get(this.id);\n const course = state.course;\n // Refresh completion icon.\n this._refreshCompletion({\n state,\n element: cm,\n });\n // Check if the current url is the cm url.\n if (window.location.href == cm.url || window.location.href == `${course.baseurl}#${cm.anchor}`) {\n this.reactive.dispatch('setPageItem', 'cm', this.id);\n this.element.scrollIntoView({block: \"center\"});\n }\n // Check if this we are displaying this activity page.\n if (Config.contextid != Config.courseContextId && Config.contextInstanceId == this.id) {\n this.reactive.dispatch('setPageItem', 'cm', this.id, true);\n this.element.scrollIntoView({block: \"center\"});\n }\n // Add anchor logic if the element is not user visible or the element hasn't URL.\n if (!cm.uservisible || !cm.url) {\n this.addEventListener(\n this.getElement(this.selectors.CM_NAME),\n 'click',\n this._activityAnchor,\n );\n }\n }\n\n /**\n * Component watchers.\n *\n * @returns {Array} of watchers\n */\n getWatchers() {\n return [\n {watch: `cm[${this.id}]:deleted`, handler: this.remove},\n {watch: `cm[${this.id}]:updated`, handler: this._refreshCm},\n {watch: `cm[${this.id}].completionstate:updated`, handler: this._refreshCompletion},\n {watch: `course.pageItem:updated`, handler: this._refreshPageItem},\n ];\n }\n\n /**\n * Update a course index cm using the state information.\n *\n * @param {object} param\n * @param {Object} param.element details the update details.\n */\n _refreshCm({element}) {\n // Update classes.\n this.element.classList.toggle(this.classes.CMHIDDEN, !element.visible);\n this.getElement(this.selectors.CM_NAME).innerHTML = element.name;\n this.element.classList.toggle(this.classes.DRAGGING, element.dragging ?? false);\n this.element.classList.toggle(this.classes.LOCKED, element.locked ?? false);\n this.element.classList.toggle(this.classes.RESTRICTIONS, element.hascmrestrictions ?? false);\n this.element.classList.toggle(this.classes.INDENTED, element.indent);\n this.locked = element.locked;\n }\n\n /**\n * Handle a page item update.\n *\n * @param {Object} details the update details\n * @param {Object} details.element the course state data.\n */\n _refreshPageItem({element}) {\n if (!element.pageItem) {\n return;\n }\n const isPageId = (element.pageItem.type == 'cm' && element.pageItem.id == this.id);\n this.element.classList.toggle(this.classes.PAGEITEM, isPageId);\n if (isPageId && !this.reactive.isEditing) {\n this.element.scrollIntoView({block: \"nearest\"});\n }\n }\n\n /**\n * Update the activity completion icon.\n *\n * @param {Object} details the update details\n * @param {Object} details.state the state data\n * @param {Object} details.element the element data\n */\n async _refreshCompletion({state, element}) {\n // No completion icons are displayed in edit mode.\n if (this.reactive.isEditing || !element.istrackeduser) {\n return;\n }\n // Check if the completion value has changed.\n const completionElement = this.getElement(this.selectors.CM_COMPLETION);\n if (completionElement.dataset.value == element.completionstate) {\n return;\n }\n\n // Collect section information from the state.\n const exporter = this.reactive.getExporter();\n const data = exporter.cmCompletion(state, element);\n\n try {\n const {html, js} = await Templates.renderForPromise(completionTemplate, data);\n Templates.replaceNode(completionElement, html, js);\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * The activity anchor event.\n *\n * @param {Event} event\n */\n _activityAnchor(event) {\n const cm = this.reactive.get('cm', this.id);\n // If the user cannot access the element but the element is present in the page\n // the new url should be an anchor link.\n const element = document.getElementById(cm.anchor);\n if (element) {\n // Marc the element as page item once the event is handled.\n setTimeout(() => {\n this.reactive.dispatch('setPageItem', 'cm', cm.id);\n }, 50);\n return;\n }\n // If the element is not present in the page we need to go to the specific section.\n const course = this.reactive.get('course');\n const section = this.reactive.get('section', cm.sectionid);\n if (!section) {\n return;\n }\n const url = `${course.baseurl}§ion=${section.number}#${cm.anchor}`;\n event.preventDefault();\n window.location = url;\n }\n}\n"],"names":["prefetchTemplate","Component","DndCmItem","create","name","selectors","CM_NAME","CM_COMPLETION","classes","CMHIDDEN","LOCKED","RESTRICTIONS","PAGEITEM","INDENTED","id","this","element","dataset","target","document","getElementById","stateReady","state","configDragDrop","cm","get","course","_refreshCompletion","window","location","href","url","baseurl","anchor","reactive","dispatch","scrollIntoView","block","Config","contextid","courseContextId","contextInstanceId","uservisible","addEventListener","getElement","_activityAnchor","getWatchers","watch","handler","remove","_refreshCm","_refreshPageItem","classList","toggle","visible","innerHTML","DRAGGING","dragging","locked","hascmrestrictions","indent","pageItem","isPageId","type","isEditing","istrackeduser","completionElement","value","completionstate","data","getExporter","cmCompletion","html","js","Templates","renderForPromise","replaceNode","error","event","setTimeout","section","sectionid","number","preventDefault"],"mappings":"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"} \ No newline at end of file diff --git a/course/format/amd/src/local/courseindex/cm.js b/course/format/amd/src/local/courseindex/cm.js index 5c0c9f5132b..0e9e4cf9257 100644 --- a/course/format/amd/src/local/courseindex/cm.js +++ b/course/format/amd/src/local/courseindex/cm.js @@ -96,8 +96,8 @@ export default class Component extends DndCmItem { this.reactive.dispatch('setPageItem', 'cm', this.id, true); this.element.scrollIntoView({block: "center"}); } - // Add anchor logic if the element is not user visible. - if (!cm.uservisible) { + // Add anchor logic if the element is not user visible or the element hasn't URL. + if (!cm.uservisible || !cm.url) { this.addEventListener( this.getElement(this.selectors.CM_NAME), 'click', diff --git a/course/format/templates/local/courseindex/cm.mustache b/course/format/templates/local/courseindex/cm.mustache index befb520474b..c5383afd1fa 100644 --- a/course/format/templates/local/courseindex/cm.mustache +++ b/course/format/templates/local/courseindex/cm.mustache @@ -36,7 +36,7 @@ {{#isactive}}active{{/isactive}} {{#hascmrestrictions}}restrictions{{/hascmrestrictions}} {{^accessvisible}}dimmed{{/accessvisible}} - {{#url}} d-flex {{/url}} {{^url}} d-flex-noedit {{/url}} + d-flex {{#indent}} indented {{/indent}}" id="{{uniqid}}-course-index-cm-{{id}}" data-for="cm" @@ -44,23 +44,21 @@ role="treeitem" > - {{#url}} - {{#uservisible}} - - {{{name}}} - - {{/uservisible}} - {{^uservisible}} - - {{{name}}} - - {{/uservisible}} - {{/url}} - {{^url}} - + {{#uservisible}} + {{{name}}} - - {{/url}} + + {{/uservisible}} + {{^uservisible}} + + {{{name}}} + + {{/uservisible}} {{#pix}} t/locked, core {{/pix}} diff --git a/course/format/tests/behat/course_courseindex.feature b/course/format/tests/behat/course_courseindex.feature index a8d988e57ea..1498e35356c 100644 --- a/course/format/tests/behat/course_courseindex.feature +++ b/course/format/tests/behat/course_courseindex.feature @@ -308,3 +308,24 @@ Feature: Course index depending on role And I follow "Switch role to..." in the user menu And I press "Student" Then I should not see "Topic 1" in the "courseindex-content" "region" + + @javascript + Scenario: Course index behaviour for activities without url + # Add a label to the course (labels doesn't have URL, because they can't be displayed in a separate page). + Given the following "activities" exist: + | activity | name | intro | course | idnumber | section | + | label | Activity sample 4 | Test label | C1 | sample4 | 2 | + # Check resources without URL, as labels, are displayed in the CI and the link goes to the main page when it is clicked. + When I am on the "sample1" "Activity" page logged in as "student1" + Then I should see "Test label" in the "#courseindex" "css_element" + And I click on "Test label" "link" in the "#courseindex" "css_element" + And I should see "Test label" in the "region-main" "region" + And I should see "Activity sample 2" in the "region-main" "region" + # Check resources without URL, as labels, are displayed for teachers too, and the link is working even when edit mode is on. + And I am on the "sample1" "Activity" page logged in as "teacher1" + And I should see "Test label" in the "#courseindex" "css_element" + And I turn editing mode on + And I should see "Test label" in the "#courseindex" "css_element" + And I click on "Test label" "link" in the "#courseindex" "css_element" + And I should see "Test label" in the "region-main" "region" + And I should see "Activity sample 2" in the "region-main" "region" diff --git a/lib/editor/atto/tests/behat/customtoolbar.feature b/lib/editor/atto/tests/behat/customtoolbar.feature index ec282c2e9c5..dfecd22fec9 100644 --- a/lib/editor/atto/tests/behat/customtoolbar.feature +++ b/lib/editor/atto/tests/behat/customtoolbar.feature @@ -14,7 +14,7 @@ Feature: Atto editor with customised toolbar | label | L1 | FixtureLink | C1 | label1 | When I log in as "admin" And I am on "Course 1" course homepage - And I follow "FixtureLink" + And I click on "FixtureLink" "link" in the "region-main" "region" @javascript Scenario: Confirm that both editors have different toolbars but still function diff --git a/lib/editor/atto/tests/behat/disablecontrol.feature b/lib/editor/atto/tests/behat/disablecontrol.feature index 893d241b3e5..b7a6678157e 100644 --- a/lib/editor/atto/tests/behat/disablecontrol.feature +++ b/lib/editor/atto/tests/behat/disablecontrol.feature @@ -14,7 +14,7 @@ Feature: Atto with enable/disable function. | label | L1 | Control Enable/Disable Atto | C1 | label1 | And I log in as "admin" And I am on "Course 1" course homepage - And I follow "Control Enable/Disable Atto" + And I click on "Control Enable/Disable Atto" "link" in the "region-main" "region" @javascript Scenario: Check disable Atto editor. diff --git a/lib/editor/textarea/tests/behat/disablecontrol.feature b/lib/editor/textarea/tests/behat/disablecontrol.feature index 9e482056a7f..bac5635b481 100644 --- a/lib/editor/textarea/tests/behat/disablecontrol.feature +++ b/lib/editor/textarea/tests/behat/disablecontrol.feature @@ -18,7 +18,7 @@ Feature: Text area with enable/disable function. And I set the field "Text editor" to "Plain text area" And I press "Save changes" And I am on "Course 1" course homepage - And I follow "Control Enable/Disable Text area" + And I click on "Control Enable/Disable Text area" "link" in the "region-main" "region" @javascript Scenario: Check disable Text area editor. diff --git a/lib/tests/behat/largeforms.feature b/lib/tests/behat/largeforms.feature index 1e6223ae0c3..57e388277e6 100644 --- a/lib/tests/behat/largeforms.feature +++ b/lib/tests/behat/largeforms.feature @@ -13,7 +13,7 @@ Feature: Forms with a large number of fields | activity | name | intro | course | idnumber | | label | L1 | FixtureLink | C1 | label1 | When I am on the "C1" "Course" page logged in as "admin" - And I follow "FixtureLink" + And I click on "FixtureLink" "link" in the "region-main" "region" # Note: These tests do not actually use JavaScript but they don't work with # the headless 'browser'. diff --git a/lib/tests/behat/readonlyform.feature b/lib/tests/behat/readonlyform.feature index bcf217ab527..2c4fae6bbd4 100644 --- a/lib/tests/behat/readonlyform.feature +++ b/lib/tests/behat/readonlyform.feature @@ -13,7 +13,7 @@ Feature: Read-only forms should work | activity | name | intro | course | idnumber | | label | L1 | Fixture link | C1 | label1 | Given I am on the "C1" "Course" page logged in as "admin" - And I follow "Fixture link" + And I click on "Fixture link" "link" in the "region-main" "region" When I expand all fieldsets Then the field "Name" matches value "Important information" @@ -26,7 +26,7 @@ Feature: Read-only forms should work | activity | name | intro | course | idnumber | | label | L1 | Fixture link | C1 | label1 | Given I am on the "C1" "Course" page logged in as "admin" - And I follow "Fixture link" + And I click on "Fixture link" "link" in the "region-main" "region" When I expand all fieldsets Then the field "Name" matches value "Important information" Then the field "Other" matches value "Other information"