From 08670beb6e9fddc28873cd197d4ee9163779eff9 Mon Sep 17 00:00:00 2001 From: Ferran Recio Date: Mon, 25 Oct 2021 11:29:37 +0200 Subject: [PATCH] MDL-72819 core_courseformat: change collapsed attribute names --- course/format/amd/build/local/content.min.js | 2 +- course/format/amd/build/local/content.min.js.map | 2 +- .../build/local/courseeditor/mutations.min.js | 2 +- .../local/courseeditor/mutations.min.js.map | 2 +- .../build/local/courseindex/courseindex.min.js | 2 +- .../local/courseindex/courseindex.min.js.map | 2 +- course/format/amd/src/local/content.js | 12 ++++++------ .../amd/src/local/courseeditor/mutations.js | 16 ++++++++-------- .../amd/src/local/courseindex/courseindex.js | 12 ++++++------ .../classes/output/local/content/section.php | 4 ++-- .../classes/output/local/state/section.php | 12 ++++++------ .../templates/local/content/movesection.mustache | 4 ++-- .../templates/local/content/section.mustache | 4 ++-- .../local/content/section/header.mustache | 6 ++++-- .../templates/local/courseindex/cm.mustache | 1 - .../local/courseindex/courseindex.mustache | 4 ++-- .../templates/local/courseindex/section.mustache | 8 ++++---- 17 files changed, 48 insertions(+), 47 deletions(-) diff --git a/course/format/amd/build/local/content.min.js b/course/format/amd/build/local/content.min.js index 8bfe2aaa49c..83bfdaaec58 100644 --- a/course/format/amd/build/local/content.min.js +++ b/course/format/amd/build/local/content.min.js @@ -1,2 +1,2 @@ -define ("core_courseformat/local/content",["exports","core/reactive","core_courseformat/courseeditor","core/inplace_editable","core_courseformat/local/content/section","core_courseformat/local/content/section/cmitem","core_course/actions","core_courseformat/local/content/actions","core_course/events"],function(a,b,c,d,e,f,g,h,i){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;d=l(d);e=l(e);f=l(f);g=l(g);h=l(h);i=k(i);function j(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;j=function(){return a};return a}function k(a){if(a&&a.__esModule){return a}if(null===a||"object"!==m(a)&&"function"!=typeof a){return{default:a}}var b=j();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function l(a){return a&&a.__esModule?a:{default:a}}function m(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){m=function(a){return typeof a}}else{m=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return m(a)}function n(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function o(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){n(h,d,e,f,g,"next",a)}function g(a){n(h,d,e,f,g,"throw",a)}f(void 0)})}}function p(a,b){var c=Object.keys(a);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(a);if(b)d=d.filter(function(b){return Object.getOwnPropertyDescriptor(a,b).enumerable});c.push.apply(c,d)}return c}function q(a){for(var b=1,c;bc.length){j=b.lastChild;if(null===j||void 0===j?void 0:null===(i=j.classList)||void 0===i?void 0:i.contains("dndupload-preview")){h=j}else{e[null!==(k=null===j||void 0===j?void 0:null===(l=j.dataset)||void 0===l?void 0:l.id)&&void 0!==k?k:0]=j}b.removeChild(j)}if(h){b.append(h)}case 10:case"end":return a.stop();}}},a)}));return function _fixOrder(){return a.apply(this,arguments)}}()}],[{key:"init",value:function init(a,d,e){return new b({element:document.getElementById(a),reactive:(0,c.getCurrentCourseEditor)(),selectors:d,sectionReturn:e})}}]);return b}(b.BaseComponent);a.default=C;return a.default}); +define ("core_courseformat/local/content",["exports","core/reactive","core_courseformat/courseeditor","core/inplace_editable","core_courseformat/local/content/section","core_courseformat/local/content/section/cmitem","core_course/actions","core_courseformat/local/content/actions","core_course/events"],function(a,b,c,d,e,f,g,h,i){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;d=l(d);e=l(e);f=l(f);g=l(g);h=l(h);i=k(i);function j(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;j=function(){return a};return a}function k(a){if(a&&a.__esModule){return a}if(null===a||"object"!==m(a)&&"function"!=typeof a){return{default:a}}var b=j();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function l(a){return a&&a.__esModule?a:{default:a}}function m(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){m=function(a){return typeof a}}else{m=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return m(a)}function n(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function o(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){n(h,d,e,f,g,"next",a)}function g(a){n(h,d,e,f,g,"throw",a)}f(void 0)})}}function p(a,b){var c=Object.keys(a);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(a);if(b)d=d.filter(function(b){return Object.getOwnPropertyDescriptor(a,b).enumerable});c.push.apply(c,d)}return c}function q(a){for(var b=1,c;bc.length){j=b.lastChild;if(null===j||void 0===j?void 0:null===(i=j.classList)||void 0===i?void 0:i.contains("dndupload-preview")){h=j}else{e[null!==(k=null===j||void 0===j?void 0:null===(l=j.dataset)||void 0===l?void 0:l.id)&&void 0!==k?k:0]=j}b.removeChild(j)}if(h){b.append(h)}case 10:case"end":return a.stop();}}},a)}));return function _fixOrder(){return a.apply(this,arguments)}}()}],[{key:"init",value:function init(a,d,e){return new b({element:document.getElementById(a),reactive:(0,c.getCurrentCourseEditor)(),selectors:d,sectionReturn:e})}}]);return b}(b.BaseComponent);a.default=C;return a.default}); //# sourceMappingURL=content.min.js.map diff --git a/course/format/amd/build/local/content.min.js.map b/course/format/amd/build/local/content.min.js.map index 3ede8af7eec..20d825da02e 100644 --- a/course/format/amd/build/local/content.min.js.map +++ b/course/format/amd/build/local/content.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../src/local/content.js"],"names":["Component","descriptor","name","selectors","SECTION","SECTION_ITEM","SECTION_CMLIST","COURSE_SECTIONLIST","CM","TOGGLER","COLLAPSE","TOGGLEALL","ACTIVITYTAG","SECTIONTAG","classes","COLLAPSED","ACTIVITY","STATEDREADY","dettachedCms","dettachedSections","sections","cms","sectionReturn","state","_indexContents","addEventListener","element","_sectionTogglers","toogleAll","getElement","_allSectionToggler","_refreshAllSectionsToggler","reactive","supportComponents","isEditing","DispatchActions","classList","add","CourseEvents","manualCompletionToggled","_completionHandler","event","sectionlink","target","closest","isChevron","section","toggler","querySelector","isCollapsed","contains","sectionId","getAttribute","dispatch","contentexpanded","preventDefault","isAllCollapsed","course","get","sectionlist","watch","handler","_reloadCm","_refreshSectionNumber","_refreshSectionCollapsed","_startProcessing","_refreshCourseSectionlist","_refreshSectionCmlist","id","Error","click","allcollapsed","allexpanded","forEach","remove","detail","cmid","completed","number","dataset","sectionid","inplace","inplaceeditable","getInplaceEditable","currentvalue","getValue","currentitemid","getItemId","rawtitle","setValue","cmlist","listparent","createCm","_createCmItem","bind","_fixOrder","createSection","_createSectionItem","_scanIndex","item","Section","CmItem","selector","index","creationhandler","items","getElements","unregister","indexed","cmitem","promise","courseActions","refreshModule","then","catch","sectionitem","refreshSection","container","newItem","document","createElement","for","append","_reloadSection","neworder","dettachedelements","createMethod","length","innerHTML","itemid","currentitem","children","insertBefore","lastchild","lastChild","dndFakeActivity","removeChild","getElementById","BaseComponent"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course index main component.\n *\n * @module core_courseformat/local/content\n * @class core_courseformat/local/content\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport inplaceeditable from 'core/inplace_editable';\nimport Section from 'core_courseformat/local/content/section';\nimport CmItem from 'core_courseformat/local/content/section/cmitem';\n// Course actions is needed for actions that are not migrated to components.\nimport courseActions from 'core_course/actions';\nimport DispatchActions from 'core_courseformat/local/content/actions';\nimport * as CourseEvents from 'core_course/events';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n *\n * @param {Object} descriptor the component descriptor\n */\n create(descriptor) {\n // Optional component name for debugging.\n this.name = 'course_format';\n // Default query selectors.\n this.selectors = {\n SECTION: `[data-for='section']`,\n SECTION_ITEM: `[data-for='section_title']`,\n SECTION_CMLIST: `[data-for='cmlist']`,\n COURSE_SECTIONLIST: `[data-for='course_sectionlist']`,\n CM: `[data-for='cmitem']`,\n TOGGLER: `[data-action=\"togglecoursecontentsection\"]`,\n COLLAPSE: `[data-toggle=\"collapse\"]`,\n TOGGLEALL: `[data-toggle=\"toggleall\"]`,\n // Formats can override the activity tag but a default one is needed to create new elements.\n ACTIVITYTAG: 'li',\n SECTIONTAG: 'li',\n };\n // Default classes to toggle on refresh.\n this.classes = {\n COLLAPSED: `collapsed`,\n // Course content classes.\n ACTIVITY: `activity`,\n STATEDREADY: `stateready`,\n SECTION: `section`,\n };\n // Array to save dettached elements during element resorting.\n this.dettachedCms = {};\n this.dettachedSections = {};\n // Index of sections and cms components.\n this.sections = {};\n this.cms = {};\n // The page section return.\n this.sectionReturn = descriptor.sectionReturn ?? 0;\n }\n\n /**\n * Static method to create a component instance form the mustahce template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @param {number} sectionReturn the content section return\n * @return {Component}\n */\n static init(target, selectors, sectionReturn) {\n return new Component({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n sectionReturn,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the state data\n */\n stateReady(state) {\n this._indexContents();\n // Activate section togglers.\n this.addEventListener(this.element, 'click', this._sectionTogglers);\n\n // Collapse/Expand all sections button.\n const toogleAll = this.getElement(this.selectors.TOGGLEALL);\n if (toogleAll) {\n this.addEventListener(toogleAll, 'click', this._allSectionToggler);\n this._refreshAllSectionsToggler(state);\n }\n\n if (this.reactive.supportComponents) {\n // Actions are only available in edit mode.\n if (this.reactive.isEditing) {\n new DispatchActions(this);\n }\n\n // Mark content as state ready.\n this.element.classList.add(this.classes.STATEDREADY);\n }\n\n // Capture completion events.\n this.addEventListener(\n this.element,\n CourseEvents.manualCompletionToggled,\n this._completionHandler\n );\n }\n\n /**\n * Setup sections toggler.\n *\n * Toggler click is delegated to the main course content element because new sections can\n * appear at any moment and this way we prevent accidental double bindings.\n *\n * @param {Event} event the triggered event\n */\n _sectionTogglers(event) {\n const sectionlink = event.target.closest(this.selectors.TOGGLER);\n const isChevron = event.target.closest(this.selectors.COLLAPSE);\n\n if (sectionlink || isChevron) {\n\n const section = event.target.closest(this.selectors.SECTION);\n const toggler = section.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (isChevron || isCollapsed) {\n // Update the state.\n const sectionId = section.getAttribute('data-id');\n this.reactive.dispatch(\n 'sectionPreferences',\n [sectionId],\n {\n contentexpanded: isCollapsed,\n },\n );\n }\n }\n }\n\n /**\n * Handle the collapse/expand all sections button.\n *\n * Toggler click is delegated to the main course content element because new sections can\n * appear at any moment and this way we prevent accidental double bindings.\n *\n * @param {Event} event the triggered event\n */\n _allSectionToggler(event) {\n event.preventDefault();\n\n const target = event.target.closest(this.selectors.TOGGLEALL);\n const isAllCollapsed = target.classList.contains(this.classes.COLLAPSED);\n\n const course = this.reactive.get('course');\n this.reactive.dispatch(\n 'sectionPreferences',\n course.sectionlist ?? [],\n {\n contentexpanded: isAllCollapsed,\n }\n );\n }\n\n /**\n * Return the component watchers.\n *\n * @returns {Array} of watchers\n */\n getWatchers() {\n // Section return is a global page variable but most formats define it just before start printing\n // the course content. This is the reason why we define this page setting here.\n this.reactive.sectionReturn = this.sectionReturn;\n\n // Check if the course format is compatible with reactive components.\n if (!this.reactive.supportComponents) {\n return [];\n }\n return [\n // State changes that require to reload some course modules.\n {watch: `cm.visible:updated`, handler: this._reloadCm},\n // Update section number and title.\n {watch: `section.number:updated`, handler: this._refreshSectionNumber},\n // Collapse and expand sections.\n {watch: `section.contentexpanded:updated`, handler: this._refreshSectionCollapsed},\n // Sections and cm sorting.\n {watch: `transaction:start`, handler: this._startProcessing},\n {watch: `course.sectionlist:updated`, handler: this._refreshCourseSectionlist},\n {watch: `section.cmlist:updated`, handler: this._refreshSectionCmlist},\n // Reindex sections and cms.\n {watch: `state:updated`, handler: this._indexContents},\n // State changes thaty require to reload course modules.\n {watch: `cm.visible:updated`, handler: this._reloadCm},\n {watch: `cm.sectionid:updated`, handler: this._reloadCm},\n ];\n }\n\n /**\n * Update section collapsed.\n *\n * @param {object} args\n * @param {Object} args.state The state data\n * @param {Object} args.element The element to update\n */\n _refreshSectionCollapsed({state, element}) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n if (!target) {\n throw new Error(`Unknown section with ID ${element.id}`);\n }\n // Check if it is already done.\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (element.contentexpanded === isCollapsed) {\n toggler.click();\n }\n\n this._refreshAllSectionsToggler(state);\n }\n\n /**\n * Refresh the collapse/expand all sections element.\n *\n * @param {Object} state The state data\n */\n _refreshAllSectionsToggler(state) {\n const target = this.getElement(this.selectors.TOGGLEALL);\n if (!target) {\n return;\n }\n // Check if we have all sections collapsed/expanded.\n let allcollapsed = true;\n let allexpanded = true;\n state.section.forEach(\n section => {\n allcollapsed = allcollapsed && !section.contentexpanded;\n allexpanded = allexpanded && section.contentexpanded;\n }\n );\n if (allcollapsed) {\n target.classList.add(this.classes.COLLAPSED);\n }\n if (allexpanded) {\n target.classList.remove(this.classes.COLLAPSED);\n }\n }\n\n /**\n * Setup the component to start a transaction.\n *\n * Some of the course actions replaces the current DOM element with a new one before updating the\n * course state. This means the component cannot preload any index properly until the transaction starts.\n *\n */\n _startProcessing() {\n // During a section or cm sorting, some elements could be dettached from the DOM and we\n // need to store somewhare in case they are needed later.\n this.dettachedCms = {};\n this.dettachedSections = {};\n }\n\n /**\n * Activity manual completion listener.\n *\n * @param {Event} event the custom ecent\n */\n _completionHandler({detail}) {\n if (detail === undefined) {\n return;\n }\n this.reactive.dispatch('cmCompletion', [detail.cmid], detail.completed);\n }\n\n /**\n * Update a course section when the section number changes.\n *\n * The courseActions module used for most course section tools still depends on css classes and\n * section numbers (not id). To prevent inconsistencies when a section is moved, we need to refresh\n * the\n *\n * Course formats can override the section title rendering so the frontend depends heavily on backend\n * rendering. Luckily in edit mode we can trigger a title update using the inplace_editable module.\n *\n * @param {Object} param\n * @param {Object} param.element details the update details.\n */\n _refreshSectionNumber({element}) {\n // Find the element.\n const target = this.getElement(this.selectors.SECTION, element.id);\n if (!target) {\n // Job done. Nothing to refresh.\n return;\n }\n // Update section numbers in all data, css and YUI attributes.\n target.id = `section-${element.number}`;\n // YUI uses section number as section id in data-sectionid, in principle if a format use components\n // don't need this sectionid attribute anymore, but we keep the compatibility in case some plugin\n // use it for legacy purposes.\n target.dataset.sectionid = element.number;\n // The data-number is the attribute used by components to store the section number.\n target.dataset.number = element.number;\n\n // Update title and title inplace editable, if any.\n const inplace = inplaceeditable.getInplaceEditable(target.querySelector(this.selectors.SECTION_ITEM));\n if (inplace) {\n // The course content HTML can be modified at any moment, so the function need to do some checkings\n // to make sure the inplace editable still represents the same itemid.\n const currentvalue = inplace.getValue();\n const currentitemid = inplace.getItemId();\n // Unnamed sections must be recalculated.\n if (inplace.getValue() === '') {\n // The value to send can be an empty value if it is a default name.\n if (currentitemid == element.id && (currentvalue != element.rawtitle || element.rawtitle == '')) {\n inplace.setValue(element.rawtitle);\n }\n }\n }\n }\n\n /**\n * Refresh a section cm list.\n *\n * @param {Object} param\n * @param {Object} param.element details the update details.\n */\n _refreshSectionCmlist({element}) {\n const cmlist = element.cmlist ?? [];\n const section = this.getElement(this.selectors.SECTION, element.id);\n const listparent = section?.querySelector(this.selectors.SECTION_CMLIST);\n // A method to create a fake element to be replaced when the item is ready.\n const createCm = this._createCmItem.bind(this);\n if (listparent) {\n this._fixOrder(listparent, cmlist, this.selectors.CM, this.dettachedCms, createCm);\n }\n }\n\n /**\n * Refresh the section list.\n *\n * @param {Object} param\n * @param {Object} param.element details the update details.\n */\n _refreshCourseSectionlist({element}) {\n // If we have a section return means we only show a single section so no need to fix order.\n if (this.reactive.sectionReturn != 0) {\n return;\n }\n const sectionlist = element.sectionlist ?? [];\n const listparent = this.getElement(this.selectors.COURSE_SECTIONLIST);\n // For now section cannot be created at a frontend level.\n const createSection = this._createSectionItem.bind(this);\n if (listparent) {\n this._fixOrder(listparent, sectionlist, this.selectors.SECTION, this.dettachedSections, createSection);\n }\n }\n\n /**\n * Regenerate content indexes.\n *\n * This method is used when a legacy action refresh some content element.\n */\n _indexContents() {\n // Find unindexed sections.\n this._scanIndex(\n this.selectors.SECTION,\n this.sections,\n (item) => {\n return new Section(item);\n }\n );\n\n // Find unindexed cms.\n this._scanIndex(\n this.selectors.CM,\n this.cms,\n (item) => {\n return new CmItem(item);\n }\n );\n }\n\n /**\n * Reindex a content (section or cm) of the course content.\n *\n * This method is used internally by _indexContents.\n *\n * @param {string} selector the DOM selector to scan\n * @param {*} index the index attribute to update\n * @param {*} creationhandler method to create a new indexed element\n */\n _scanIndex(selector, index, creationhandler) {\n const items = this.getElements(`${selector}:not([data-indexed])`);\n items.forEach((item) => {\n if (!item?.dataset?.id) {\n return;\n }\n // Delete previous item component.\n if (index[item.dataset.id] !== undefined) {\n index[item.dataset.id].unregister();\n }\n // Create the new component.\n index[item.dataset.id] = creationhandler({\n ...this,\n element: item,\n });\n // Mark as indexed.\n item.dataset.indexed = true;\n });\n }\n\n /**\n * Reload a course module contents.\n *\n * Most course module HTML is still strongly backend dependant.\n * Some changes require to get a new version of the module.\n *\n * @param {object} param0 the watcher details\n * @param {object} param0.element the state object\n */\n _reloadCm({element}) {\n const cmitem = this.getElement(this.selectors.CM, element.id);\n if (cmitem) {\n const promise = courseActions.refreshModule(cmitem, element.id);\n promise.then(() => {\n this._indexContents();\n return;\n }).catch();\n }\n }\n\n /**\n * Reload a course section contents.\n *\n * Section HTML is still strongly backend dependant.\n * Some changes require to get a new version of the section.\n *\n * @param {details} param0 the watcher details\n * @param {object} param0.element the state object\n */\n _reloadSection({element}) {\n const sectionitem = this.getElement(this.selectors.SECTION, element.id);\n if (sectionitem) {\n const promise = courseActions.refreshSection(sectionitem, element.id);\n promise.then(() => {\n this._indexContents();\n return;\n }).catch();\n }\n }\n\n /**\n * Create a new course module item in a section.\n *\n * Thos method will append a fake item in the container and trigger an ajax request to\n * replace the fake element by the real content.\n *\n * @param {Element} container the container element (section)\n * @param {Number} cmid the course-module ID\n * @returns {Element} the created element\n */\n _createCmItem(container, cmid) {\n const newItem = document.createElement(this.selectors.ACTIVITYTAG);\n newItem.dataset.for = 'cmitem';\n newItem.dataset.id = cmid;\n // The legacy actions.js requires a specific ID and class to refresh the CM.\n newItem.id = `module-${cmid}`;\n newItem.classList.add(this.classes.ACTIVITY);\n container.append(newItem);\n this._reloadCm({\n element: this.reactive.get('cm', cmid),\n });\n return newItem;\n }\n\n /**\n * Create a new section item.\n *\n * This method will append a fake item in the container and trigger an ajax request to\n * replace the fake element by the real content.\n *\n * @param {Element} container the container element (section)\n * @param {Number} sectionid the course-module ID\n * @returns {Element} the created element\n */\n _createSectionItem(container, sectionid) {\n const section = this.reactive.get('section', sectionid);\n const newItem = document.createElement(this.selectors.SECTIONTAG);\n newItem.dataset.for = 'section';\n newItem.dataset.id = sectionid;\n newItem.dataset.number = section.number;\n // The legacy actions.js requires a specific ID and class to refresh the section.\n newItem.id = `section-${sectionid}`;\n newItem.classList.add(this.classes.SECTION);\n container.append(newItem);\n this._reloadSection({\n element: section,\n });\n return newItem;\n }\n\n /**\n * Fix/reorder the section or cms order.\n *\n * @param {Element} container the HTML element to reorder.\n * @param {Array} neworder an array with the ids order\n * @param {string} selector the element selector\n * @param {Object} dettachedelements a list of dettached elements\n * @param {function} createMethod method to create missing elements\n */\n async _fixOrder(container, neworder, selector, dettachedelements, createMethod) {\n if (container === undefined) {\n return;\n }\n\n // Empty lists should not be visible.\n if (!neworder.length) {\n container.classList.add('hidden');\n container.innerHTML = '';\n return;\n }\n\n // Grant the list is visible (in case it was empty).\n container.classList.remove('hidden');\n\n // Move the elements in order at the beginning of the list.\n neworder.forEach((itemid, index) => {\n let item = this.getElement(selector, itemid) ?? dettachedelements[itemid] ?? createMethod(container, itemid);\n if (item === undefined) {\n // Missing elements cannot be sorted.\n return;\n }\n // Get the current elemnt at that position.\n const currentitem = container.children[index];\n if (currentitem === undefined) {\n container.append(item);\n return;\n }\n if (currentitem !== item) {\n container.insertBefore(item, currentitem);\n }\n });\n\n // Dndupload add a fake element we need to keep.\n let dndFakeActivity;\n\n // Remove the remaining elements.\n while (container.children.length > neworder.length) {\n const lastchild = container.lastChild;\n if (lastchild?.classList?.contains('dndupload-preview')) {\n dndFakeActivity = lastchild;\n } else {\n dettachedelements[lastchild?.dataset?.id ?? 0] = lastchild;\n }\n container.removeChild(lastchild);\n }\n // Restore dndupload fake element.\n if (dndFakeActivity) {\n container.append(dndFakeActivity);\n }\n }\n}\n"],"file":"content.min.js"} \ No newline at end of file +{"version":3,"sources":["../../src/local/content.js"],"names":["Component","descriptor","name","selectors","SECTION","SECTION_ITEM","SECTION_CMLIST","COURSE_SECTIONLIST","CM","TOGGLER","COLLAPSE","TOGGLEALL","ACTIVITYTAG","SECTIONTAG","classes","COLLAPSED","ACTIVITY","STATEDREADY","dettachedCms","dettachedSections","sections","cms","sectionReturn","state","_indexContents","addEventListener","element","_sectionTogglers","toogleAll","getElement","_allSectionToggler","_refreshAllSectionsToggler","reactive","supportComponents","isEditing","DispatchActions","classList","add","CourseEvents","manualCompletionToggled","_completionHandler","event","sectionlink","target","closest","isChevron","section","toggler","querySelector","isCollapsed","contains","sectionId","getAttribute","dispatch","contentcollapsed","preventDefault","isAllCollapsed","course","get","sectionlist","watch","handler","_reloadCm","_refreshSectionNumber","_refreshSectionCollapsed","_startProcessing","_refreshCourseSectionlist","_refreshSectionCmlist","id","Error","click","allcollapsed","allexpanded","forEach","remove","detail","cmid","completed","number","dataset","sectionid","inplace","inplaceeditable","getInplaceEditable","currentvalue","getValue","currentitemid","getItemId","rawtitle","setValue","cmlist","listparent","createCm","_createCmItem","bind","_fixOrder","createSection","_createSectionItem","_scanIndex","item","Section","CmItem","selector","index","creationhandler","items","getElements","unregister","indexed","cmitem","promise","courseActions","refreshModule","then","catch","sectionitem","refreshSection","container","newItem","document","createElement","for","append","_reloadSection","neworder","dettachedelements","createMethod","length","innerHTML","itemid","currentitem","children","insertBefore","lastchild","lastChild","dndFakeActivity","removeChild","getElementById","BaseComponent"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course index main component.\n *\n * @module core_courseformat/local/content\n * @class core_courseformat/local/content\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport inplaceeditable from 'core/inplace_editable';\nimport Section from 'core_courseformat/local/content/section';\nimport CmItem from 'core_courseformat/local/content/section/cmitem';\n// Course actions is needed for actions that are not migrated to components.\nimport courseActions from 'core_course/actions';\nimport DispatchActions from 'core_courseformat/local/content/actions';\nimport * as CourseEvents from 'core_course/events';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n *\n * @param {Object} descriptor the component descriptor\n */\n create(descriptor) {\n // Optional component name for debugging.\n this.name = 'course_format';\n // Default query selectors.\n this.selectors = {\n SECTION: `[data-for='section']`,\n SECTION_ITEM: `[data-for='section_title']`,\n SECTION_CMLIST: `[data-for='cmlist']`,\n COURSE_SECTIONLIST: `[data-for='course_sectionlist']`,\n CM: `[data-for='cmitem']`,\n TOGGLER: `[data-action=\"togglecoursecontentsection\"]`,\n COLLAPSE: `[data-toggle=\"collapse\"]`,\n TOGGLEALL: `[data-toggle=\"toggleall\"]`,\n // Formats can override the activity tag but a default one is needed to create new elements.\n ACTIVITYTAG: 'li',\n SECTIONTAG: 'li',\n };\n // Default classes to toggle on refresh.\n this.classes = {\n COLLAPSED: `collapsed`,\n // Course content classes.\n ACTIVITY: `activity`,\n STATEDREADY: `stateready`,\n SECTION: `section`,\n };\n // Array to save dettached elements during element resorting.\n this.dettachedCms = {};\n this.dettachedSections = {};\n // Index of sections and cms components.\n this.sections = {};\n this.cms = {};\n // The page section return.\n this.sectionReturn = descriptor.sectionReturn ?? 0;\n }\n\n /**\n * Static method to create a component instance form the mustahce template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @param {number} sectionReturn the content section return\n * @return {Component}\n */\n static init(target, selectors, sectionReturn) {\n return new Component({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n sectionReturn,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {Object} state the state data\n */\n stateReady(state) {\n this._indexContents();\n // Activate section togglers.\n this.addEventListener(this.element, 'click', this._sectionTogglers);\n\n // Collapse/Expand all sections button.\n const toogleAll = this.getElement(this.selectors.TOGGLEALL);\n if (toogleAll) {\n this.addEventListener(toogleAll, 'click', this._allSectionToggler);\n this._refreshAllSectionsToggler(state);\n }\n\n if (this.reactive.supportComponents) {\n // Actions are only available in edit mode.\n if (this.reactive.isEditing) {\n new DispatchActions(this);\n }\n\n // Mark content as state ready.\n this.element.classList.add(this.classes.STATEDREADY);\n }\n\n // Capture completion events.\n this.addEventListener(\n this.element,\n CourseEvents.manualCompletionToggled,\n this._completionHandler\n );\n }\n\n /**\n * Setup sections toggler.\n *\n * Toggler click is delegated to the main course content element because new sections can\n * appear at any moment and this way we prevent accidental double bindings.\n *\n * @param {Event} event the triggered event\n */\n _sectionTogglers(event) {\n const sectionlink = event.target.closest(this.selectors.TOGGLER);\n const isChevron = event.target.closest(this.selectors.COLLAPSE);\n\n if (sectionlink || isChevron) {\n\n const section = event.target.closest(this.selectors.SECTION);\n const toggler = section.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (isChevron || isCollapsed) {\n // Update the state.\n const sectionId = section.getAttribute('data-id');\n this.reactive.dispatch(\n 'sectionPreferences',\n [sectionId],\n {\n contentcollapsed: !isCollapsed,\n },\n );\n }\n }\n }\n\n /**\n * Handle the collapse/expand all sections button.\n *\n * Toggler click is delegated to the main course content element because new sections can\n * appear at any moment and this way we prevent accidental double bindings.\n *\n * @param {Event} event the triggered event\n */\n _allSectionToggler(event) {\n event.preventDefault();\n\n const target = event.target.closest(this.selectors.TOGGLEALL);\n const isAllCollapsed = target.classList.contains(this.classes.COLLAPSED);\n\n const course = this.reactive.get('course');\n this.reactive.dispatch(\n 'sectionPreferences',\n course.sectionlist ?? [],\n {\n contentcollapsed: !isAllCollapsed,\n }\n );\n }\n\n /**\n * Return the component watchers.\n *\n * @returns {Array} of watchers\n */\n getWatchers() {\n // Section return is a global page variable but most formats define it just before start printing\n // the course content. This is the reason why we define this page setting here.\n this.reactive.sectionReturn = this.sectionReturn;\n\n // Check if the course format is compatible with reactive components.\n if (!this.reactive.supportComponents) {\n return [];\n }\n return [\n // State changes that require to reload some course modules.\n {watch: `cm.visible:updated`, handler: this._reloadCm},\n // Update section number and title.\n {watch: `section.number:updated`, handler: this._refreshSectionNumber},\n // Collapse and expand sections.\n {watch: `section.contentcollapsed:updated`, handler: this._refreshSectionCollapsed},\n // Sections and cm sorting.\n {watch: `transaction:start`, handler: this._startProcessing},\n {watch: `course.sectionlist:updated`, handler: this._refreshCourseSectionlist},\n {watch: `section.cmlist:updated`, handler: this._refreshSectionCmlist},\n // Reindex sections and cms.\n {watch: `state:updated`, handler: this._indexContents},\n // State changes thaty require to reload course modules.\n {watch: `cm.visible:updated`, handler: this._reloadCm},\n {watch: `cm.sectionid:updated`, handler: this._reloadCm},\n ];\n }\n\n /**\n * Update section collapsed.\n *\n * @param {object} args\n * @param {Object} args.state The state data\n * @param {Object} args.element The element to update\n */\n _refreshSectionCollapsed({state, element}) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n if (!target) {\n throw new Error(`Unknown section with ID ${element.id}`);\n }\n // Check if it is already done.\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (element.contentcollapsed !== isCollapsed) {\n toggler.click();\n }\n\n this._refreshAllSectionsToggler(state);\n }\n\n /**\n * Refresh the collapse/expand all sections element.\n *\n * @param {Object} state The state data\n */\n _refreshAllSectionsToggler(state) {\n const target = this.getElement(this.selectors.TOGGLEALL);\n if (!target) {\n return;\n }\n // Check if we have all sections collapsed/expanded.\n let allcollapsed = true;\n let allexpanded = true;\n state.section.forEach(\n section => {\n allcollapsed = allcollapsed && section.contentcollapsed;\n allexpanded = allexpanded && !section.contentcollapsed;\n }\n );\n if (allcollapsed) {\n target.classList.add(this.classes.COLLAPSED);\n }\n if (allexpanded) {\n target.classList.remove(this.classes.COLLAPSED);\n }\n }\n\n /**\n * Setup the component to start a transaction.\n *\n * Some of the course actions replaces the current DOM element with a new one before updating the\n * course state. This means the component cannot preload any index properly until the transaction starts.\n *\n */\n _startProcessing() {\n // During a section or cm sorting, some elements could be dettached from the DOM and we\n // need to store somewhare in case they are needed later.\n this.dettachedCms = {};\n this.dettachedSections = {};\n }\n\n /**\n * Activity manual completion listener.\n *\n * @param {Event} event the custom ecent\n */\n _completionHandler({detail}) {\n if (detail === undefined) {\n return;\n }\n this.reactive.dispatch('cmCompletion', [detail.cmid], detail.completed);\n }\n\n /**\n * Update a course section when the section number changes.\n *\n * The courseActions module used for most course section tools still depends on css classes and\n * section numbers (not id). To prevent inconsistencies when a section is moved, we need to refresh\n * the\n *\n * Course formats can override the section title rendering so the frontend depends heavily on backend\n * rendering. Luckily in edit mode we can trigger a title update using the inplace_editable module.\n *\n * @param {Object} param\n * @param {Object} param.element details the update details.\n */\n _refreshSectionNumber({element}) {\n // Find the element.\n const target = this.getElement(this.selectors.SECTION, element.id);\n if (!target) {\n // Job done. Nothing to refresh.\n return;\n }\n // Update section numbers in all data, css and YUI attributes.\n target.id = `section-${element.number}`;\n // YUI uses section number as section id in data-sectionid, in principle if a format use components\n // don't need this sectionid attribute anymore, but we keep the compatibility in case some plugin\n // use it for legacy purposes.\n target.dataset.sectionid = element.number;\n // The data-number is the attribute used by components to store the section number.\n target.dataset.number = element.number;\n\n // Update title and title inplace editable, if any.\n const inplace = inplaceeditable.getInplaceEditable(target.querySelector(this.selectors.SECTION_ITEM));\n if (inplace) {\n // The course content HTML can be modified at any moment, so the function need to do some checkings\n // to make sure the inplace editable still represents the same itemid.\n const currentvalue = inplace.getValue();\n const currentitemid = inplace.getItemId();\n // Unnamed sections must be recalculated.\n if (inplace.getValue() === '') {\n // The value to send can be an empty value if it is a default name.\n if (currentitemid == element.id && (currentvalue != element.rawtitle || element.rawtitle == '')) {\n inplace.setValue(element.rawtitle);\n }\n }\n }\n }\n\n /**\n * Refresh a section cm list.\n *\n * @param {Object} param\n * @param {Object} param.element details the update details.\n */\n _refreshSectionCmlist({element}) {\n const cmlist = element.cmlist ?? [];\n const section = this.getElement(this.selectors.SECTION, element.id);\n const listparent = section?.querySelector(this.selectors.SECTION_CMLIST);\n // A method to create a fake element to be replaced when the item is ready.\n const createCm = this._createCmItem.bind(this);\n if (listparent) {\n this._fixOrder(listparent, cmlist, this.selectors.CM, this.dettachedCms, createCm);\n }\n }\n\n /**\n * Refresh the section list.\n *\n * @param {Object} param\n * @param {Object} param.element details the update details.\n */\n _refreshCourseSectionlist({element}) {\n // If we have a section return means we only show a single section so no need to fix order.\n if (this.reactive.sectionReturn != 0) {\n return;\n }\n const sectionlist = element.sectionlist ?? [];\n const listparent = this.getElement(this.selectors.COURSE_SECTIONLIST);\n // For now section cannot be created at a frontend level.\n const createSection = this._createSectionItem.bind(this);\n if (listparent) {\n this._fixOrder(listparent, sectionlist, this.selectors.SECTION, this.dettachedSections, createSection);\n }\n }\n\n /**\n * Regenerate content indexes.\n *\n * This method is used when a legacy action refresh some content element.\n */\n _indexContents() {\n // Find unindexed sections.\n this._scanIndex(\n this.selectors.SECTION,\n this.sections,\n (item) => {\n return new Section(item);\n }\n );\n\n // Find unindexed cms.\n this._scanIndex(\n this.selectors.CM,\n this.cms,\n (item) => {\n return new CmItem(item);\n }\n );\n }\n\n /**\n * Reindex a content (section or cm) of the course content.\n *\n * This method is used internally by _indexContents.\n *\n * @param {string} selector the DOM selector to scan\n * @param {*} index the index attribute to update\n * @param {*} creationhandler method to create a new indexed element\n */\n _scanIndex(selector, index, creationhandler) {\n const items = this.getElements(`${selector}:not([data-indexed])`);\n items.forEach((item) => {\n if (!item?.dataset?.id) {\n return;\n }\n // Delete previous item component.\n if (index[item.dataset.id] !== undefined) {\n index[item.dataset.id].unregister();\n }\n // Create the new component.\n index[item.dataset.id] = creationhandler({\n ...this,\n element: item,\n });\n // Mark as indexed.\n item.dataset.indexed = true;\n });\n }\n\n /**\n * Reload a course module contents.\n *\n * Most course module HTML is still strongly backend dependant.\n * Some changes require to get a new version of the module.\n *\n * @param {object} param0 the watcher details\n * @param {object} param0.element the state object\n */\n _reloadCm({element}) {\n const cmitem = this.getElement(this.selectors.CM, element.id);\n if (cmitem) {\n const promise = courseActions.refreshModule(cmitem, element.id);\n promise.then(() => {\n this._indexContents();\n return;\n }).catch();\n }\n }\n\n /**\n * Reload a course section contents.\n *\n * Section HTML is still strongly backend dependant.\n * Some changes require to get a new version of the section.\n *\n * @param {details} param0 the watcher details\n * @param {object} param0.element the state object\n */\n _reloadSection({element}) {\n const sectionitem = this.getElement(this.selectors.SECTION, element.id);\n if (sectionitem) {\n const promise = courseActions.refreshSection(sectionitem, element.id);\n promise.then(() => {\n this._indexContents();\n return;\n }).catch();\n }\n }\n\n /**\n * Create a new course module item in a section.\n *\n * Thos method will append a fake item in the container and trigger an ajax request to\n * replace the fake element by the real content.\n *\n * @param {Element} container the container element (section)\n * @param {Number} cmid the course-module ID\n * @returns {Element} the created element\n */\n _createCmItem(container, cmid) {\n const newItem = document.createElement(this.selectors.ACTIVITYTAG);\n newItem.dataset.for = 'cmitem';\n newItem.dataset.id = cmid;\n // The legacy actions.js requires a specific ID and class to refresh the CM.\n newItem.id = `module-${cmid}`;\n newItem.classList.add(this.classes.ACTIVITY);\n container.append(newItem);\n this._reloadCm({\n element: this.reactive.get('cm', cmid),\n });\n return newItem;\n }\n\n /**\n * Create a new section item.\n *\n * This method will append a fake item in the container and trigger an ajax request to\n * replace the fake element by the real content.\n *\n * @param {Element} container the container element (section)\n * @param {Number} sectionid the course-module ID\n * @returns {Element} the created element\n */\n _createSectionItem(container, sectionid) {\n const section = this.reactive.get('section', sectionid);\n const newItem = document.createElement(this.selectors.SECTIONTAG);\n newItem.dataset.for = 'section';\n newItem.dataset.id = sectionid;\n newItem.dataset.number = section.number;\n // The legacy actions.js requires a specific ID and class to refresh the section.\n newItem.id = `section-${sectionid}`;\n newItem.classList.add(this.classes.SECTION);\n container.append(newItem);\n this._reloadSection({\n element: section,\n });\n return newItem;\n }\n\n /**\n * Fix/reorder the section or cms order.\n *\n * @param {Element} container the HTML element to reorder.\n * @param {Array} neworder an array with the ids order\n * @param {string} selector the element selector\n * @param {Object} dettachedelements a list of dettached elements\n * @param {function} createMethod method to create missing elements\n */\n async _fixOrder(container, neworder, selector, dettachedelements, createMethod) {\n if (container === undefined) {\n return;\n }\n\n // Empty lists should not be visible.\n if (!neworder.length) {\n container.classList.add('hidden');\n container.innerHTML = '';\n return;\n }\n\n // Grant the list is visible (in case it was empty).\n container.classList.remove('hidden');\n\n // Move the elements in order at the beginning of the list.\n neworder.forEach((itemid, index) => {\n let item = this.getElement(selector, itemid) ?? dettachedelements[itemid] ?? createMethod(container, itemid);\n if (item === undefined) {\n // Missing elements cannot be sorted.\n return;\n }\n // Get the current elemnt at that position.\n const currentitem = container.children[index];\n if (currentitem === undefined) {\n container.append(item);\n return;\n }\n if (currentitem !== item) {\n container.insertBefore(item, currentitem);\n }\n });\n\n // Dndupload add a fake element we need to keep.\n let dndFakeActivity;\n\n // Remove the remaining elements.\n while (container.children.length > neworder.length) {\n const lastchild = container.lastChild;\n if (lastchild?.classList?.contains('dndupload-preview')) {\n dndFakeActivity = lastchild;\n } else {\n dettachedelements[lastchild?.dataset?.id ?? 0] = lastchild;\n }\n container.removeChild(lastchild);\n }\n // Restore dndupload fake element.\n if (dndFakeActivity) {\n container.append(dndFakeActivity);\n }\n }\n}\n"],"file":"content.min.js"} \ No newline at end of file diff --git a/course/format/amd/build/local/courseeditor/mutations.min.js b/course/format/amd/build/local/courseeditor/mutations.min.js index f697831a819..2ec176fe895 100644 --- a/course/format/amd/build/local/courseeditor/mutations.min.js +++ b/course/format/amd/build/local/courseeditor/mutations.min.js @@ -1,2 +1,2 @@ -define ("core_courseformat/local/courseeditor/mutations",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);function c(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function d(a){return function(){var b=this,d=arguments;return new Promise(function(e,f){var i=a.apply(b,d);function g(a){c(i,e,f,g,h,"next",a)}function h(a){c(i,e,f,g,h,"throw",a)}g(void 0)})}}function e(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function f(a,b){for(var c=0,d;c.\n\nimport ajax from 'core/ajax';\n\n/**\n * Default mutation manager\n *\n * @module core_courseformat/local/courseeditor/mutations\n * @class core_courseformat/local/courseeditor/mutations\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default class {\n\n // All course editor mutations for Moodle 4.0 will be located in this file.\n\n /**\n * Private method to call core_courseformat_update_course webservice.\n *\n * @method _callEditWebservice\n * @param {string} action\n * @param {number} courseId\n * @param {array} ids\n * @param {number} targetSectionId optional target section id (for moving actions)\n * @param {number} targetCmId optional target cm id (for moving actions)\n */\n async _callEditWebservice(action, courseId, ids, targetSectionId, targetCmId) {\n const args = {\n action,\n courseid: courseId,\n ids,\n };\n if (targetSectionId) {\n args.targetsectionid = targetSectionId;\n }\n if (targetCmId) {\n args.targetcmid = targetCmId;\n }\n let ajaxresult = await ajax.call([{\n methodname: 'core_courseformat_update_course',\n args,\n }])[0];\n return JSON.parse(ajaxresult);\n }\n\n\n /**\n * Mutation module initialize.\n *\n * The reactive instance will execute this method when addMutations or setMutation is invoked.\n *\n * @param {StateManager} stateManager the state manager\n */\n init(stateManager) {\n // Add a method to prepare the fields when some update is comming from the server.\n stateManager.addUpdateTypes({\n prepareFields: this._prepareFields,\n });\n }\n\n /**\n * Add default values to state elements.\n *\n * This method is called every time a webservice returns a update state message.\n *\n * @param {Object} stateManager the state manager\n * @param {String} updateName the state element to update\n * @param {Object} fields the new data\n * @returns {Object} final fields data\n */\n _prepareFields(stateManager, updateName, fields) {\n // Any update should unlock the element.\n fields.locked = false;\n return fields;\n }\n\n /**\n * Move course modules to specific course location.\n *\n * Note that one of targetSectionId or targetCmId should be provided in order to identify the\n * new location:\n * - targetCmId: the activities will be located avobe the target cm. The targetSectionId\n * value will be ignored in this case.\n * - targetSectionId: the activities will be appended to the section. In this case\n * targetSectionId should not be present.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} cmids the list of cm ids to move\n * @param {number} targetSectionId the target section id\n * @param {number} targetCmId the target course module id\n */\n async cmMove(stateManager, cmids, targetSectionId, targetCmId) {\n if (!targetSectionId && !targetCmId) {\n throw new Error(`Mutation cmMove requires targetSectionId or targetCmId`);\n }\n const course = stateManager.get('course');\n this.cmLock(stateManager, cmids, true);\n const updates = await this._callEditWebservice('cm_move', course.id, cmids, targetSectionId, targetCmId);\n stateManager.processUpdates(updates);\n this.cmLock(stateManager, cmids, false);\n }\n\n /**\n * Move course modules to specific course location.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} sectionIds the list of section ids to move\n * @param {number} targetSectionId the target section id\n */\n async sectionMove(stateManager, sectionIds, targetSectionId) {\n if (!targetSectionId) {\n throw new Error(`Mutation sectionMove requires targetSectionId`);\n }\n const course = stateManager.get('course');\n this.sectionLock(stateManager, sectionIds, true);\n const updates = await this._callEditWebservice('section_move', course.id, sectionIds, targetSectionId);\n stateManager.processUpdates(updates);\n this.sectionLock(stateManager, sectionIds, false);\n }\n\n /**\n * Add a new section to a specific course location.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {number} targetSectionId optional the target section id\n */\n async addSection(stateManager, targetSectionId) {\n if (!targetSectionId) {\n targetSectionId = 0;\n }\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('section_add', course.id, [], targetSectionId);\n stateManager.processUpdates(updates);\n }\n\n /**\n * Delete sections.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} sectionIds the list of course modules ids\n */\n async sectionDelete(stateManager, sectionIds) {\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('section_delete', course.id, sectionIds);\n stateManager.processUpdates(updates);\n }\n\n /**\n * Mark or unmark course modules as dragging.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} cmIds the list of course modules ids\n * @param {bool} dragValue the new dragging value\n */\n cmDrag(stateManager, cmIds, dragValue) {\n this._setElementsValue(stateManager, 'cm', cmIds, 'dragging', dragValue);\n }\n\n /**\n * Mark or unmark course sections as dragging.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} sectionIds the list of section ids\n * @param {bool} dragValue the new dragging value\n */\n sectionDrag(stateManager, sectionIds, dragValue) {\n this._setElementsValue(stateManager, 'section', sectionIds, 'dragging', dragValue);\n }\n\n /**\n * Mark or unmark course modules as complete.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} cmIds the list of course modules ids\n * @param {bool} complete the new completion value\n */\n cmCompletion(stateManager, cmIds, complete) {\n const newValue = (complete) ? 1 : 0;\n this._setElementsValue(stateManager, 'cm', cmIds, 'completionstate', newValue);\n }\n\n /**\n * Lock or unlock course modules.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} cmIds the list of course modules ids\n * @param {bool} lockValue the new locked value\n */\n cmLock(stateManager, cmIds, lockValue) {\n this._setElementsValue(stateManager, 'cm', cmIds, 'locked', lockValue);\n }\n\n /**\n * Lock or unlock course sections.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} sectionIds the list of section ids\n * @param {bool} lockValue the new locked value\n */\n sectionLock(stateManager, sectionIds, lockValue) {\n this._setElementsValue(stateManager, 'section', sectionIds, 'locked', lockValue);\n }\n\n _setElementsValue(stateManager, name, ids, fieldName, newValue) {\n stateManager.setReadOnly(false);\n ids.forEach((id) => {\n const element = stateManager.get(name, id);\n if (element) {\n element[fieldName] = newValue;\n }\n });\n stateManager.setReadOnly(true);\n }\n\n /**\n * Unlock all course elements.\n *\n * @param {StateManager} stateManager the current state manager\n */\n unlockAll(stateManager) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n state.section.forEach((section) => {\n section.locked = false;\n });\n state.cm.forEach((cm) => {\n cm.locked = false;\n });\n stateManager.setReadOnly(true);\n }\n\n /*\n * Get updated user preferences and state data related to some section ids.\n *\n * @param {StateManager} stateManager the current state\n * @param {array} sectionIds the list of section ids to update\n * @param {Object} preferences the new preferences values\n */\n async sectionPreferences(stateManager, sectionIds, preferences) {\n stateManager.setReadOnly(false);\n // Check if we need to update preferences.\n let updatePreferences = false;\n sectionIds.forEach(sectionId => {\n const section = stateManager.get('section', sectionId);\n if (section === undefined) {\n return;\n }\n let newValue = preferences.contentexpanded ?? section.contentexpanded;\n if (section.contentexpanded != newValue) {\n section.contentexpanded = newValue;\n updatePreferences = true;\n }\n newValue = preferences.isactive ?? section.isactive;\n if (section.isactive != newValue) {\n section.isactive = newValue;\n updatePreferences = true;\n }\n });\n stateManager.setReadOnly(true);\n\n if (updatePreferences) {\n // Build the preference structures.\n const course = stateManager.get('course');\n const state = stateManager.state;\n const prefKey = `coursesectionspreferences_${course.id}`;\n const preferences = {\n contentcollapsed: [],\n indexcollapsed: [],\n };\n state.section.forEach(section => {\n if (!section.contentexpanded) {\n preferences.contentcollapsed.push(section.id);\n }\n if (!section.isactive) {\n preferences.indexcollapsed.push(section.id);\n }\n });\n const jsonString = JSON.stringify(preferences);\n M.util.set_user_preference(prefKey, jsonString);\n }\n }\n\n /**\n * Get updated state data related to some cm ids.\n *\n * @method cmState\n * @param {StateManager} stateManager the current state\n * @param {array} cmids the list of cm ids to update\n */\n async cmState(stateManager, cmids) {\n this.cmLock(stateManager, cmids, true);\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('cm_state', course.id, cmids);\n stateManager.processUpdates(updates);\n this.cmLock(stateManager, cmids, false);\n }\n\n /**\n * Get updated state data related to some section ids.\n *\n * @method sectionState\n * @param {StateManager} stateManager the current state\n * @param {array} sectionIds the list of section ids to update\n */\n async sectionState(stateManager, sectionIds) {\n this.sectionLock(stateManager, sectionIds, true);\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('section_state', course.id, sectionIds);\n stateManager.processUpdates(updates);\n this.sectionLock(stateManager, sectionIds, false);\n }\n\n /**\n * Get the full updated state data of the course.\n *\n * @param {StateManager} stateManager the current state\n */\n async courseState(stateManager) {\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('course_state', course.id);\n stateManager.processUpdates(updates);\n }\n\n}\n"],"file":"mutations.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/courseeditor/mutations.js"],"names":["action","courseId","ids","targetSectionId","targetCmId","args","courseid","targetsectionid","targetcmid","ajax","call","methodname","ajaxresult","JSON","parse","stateManager","addUpdateTypes","prepareFields","_prepareFields","updateName","fields","locked","cmids","Error","course","get","cmLock","_callEditWebservice","id","updates","processUpdates","sectionIds","sectionLock","cmIds","dragValue","_setElementsValue","complete","newValue","lockValue","name","fieldName","setReadOnly","forEach","element","state","section","cm","preferences","updatePreferences","sectionId","contentcollapsed","indexcollapsed","prefKey","push","jsonString","stringify","M","util","set_user_preference"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\nimport ajax from 'core/ajax';\n\n/**\n * Default mutation manager\n *\n * @module core_courseformat/local/courseeditor/mutations\n * @class core_courseformat/local/courseeditor/mutations\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default class {\n\n // All course editor mutations for Moodle 4.0 will be located in this file.\n\n /**\n * Private method to call core_courseformat_update_course webservice.\n *\n * @method _callEditWebservice\n * @param {string} action\n * @param {number} courseId\n * @param {array} ids\n * @param {number} targetSectionId optional target section id (for moving actions)\n * @param {number} targetCmId optional target cm id (for moving actions)\n */\n async _callEditWebservice(action, courseId, ids, targetSectionId, targetCmId) {\n const args = {\n action,\n courseid: courseId,\n ids,\n };\n if (targetSectionId) {\n args.targetsectionid = targetSectionId;\n }\n if (targetCmId) {\n args.targetcmid = targetCmId;\n }\n let ajaxresult = await ajax.call([{\n methodname: 'core_courseformat_update_course',\n args,\n }])[0];\n return JSON.parse(ajaxresult);\n }\n\n\n /**\n * Mutation module initialize.\n *\n * The reactive instance will execute this method when addMutations or setMutation is invoked.\n *\n * @param {StateManager} stateManager the state manager\n */\n init(stateManager) {\n // Add a method to prepare the fields when some update is comming from the server.\n stateManager.addUpdateTypes({\n prepareFields: this._prepareFields,\n });\n }\n\n /**\n * Add default values to state elements.\n *\n * This method is called every time a webservice returns a update state message.\n *\n * @param {Object} stateManager the state manager\n * @param {String} updateName the state element to update\n * @param {Object} fields the new data\n * @returns {Object} final fields data\n */\n _prepareFields(stateManager, updateName, fields) {\n // Any update should unlock the element.\n fields.locked = false;\n return fields;\n }\n\n /**\n * Move course modules to specific course location.\n *\n * Note that one of targetSectionId or targetCmId should be provided in order to identify the\n * new location:\n * - targetCmId: the activities will be located avobe the target cm. The targetSectionId\n * value will be ignored in this case.\n * - targetSectionId: the activities will be appended to the section. In this case\n * targetSectionId should not be present.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} cmids the list of cm ids to move\n * @param {number} targetSectionId the target section id\n * @param {number} targetCmId the target course module id\n */\n async cmMove(stateManager, cmids, targetSectionId, targetCmId) {\n if (!targetSectionId && !targetCmId) {\n throw new Error(`Mutation cmMove requires targetSectionId or targetCmId`);\n }\n const course = stateManager.get('course');\n this.cmLock(stateManager, cmids, true);\n const updates = await this._callEditWebservice('cm_move', course.id, cmids, targetSectionId, targetCmId);\n stateManager.processUpdates(updates);\n this.cmLock(stateManager, cmids, false);\n }\n\n /**\n * Move course modules to specific course location.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} sectionIds the list of section ids to move\n * @param {number} targetSectionId the target section id\n */\n async sectionMove(stateManager, sectionIds, targetSectionId) {\n if (!targetSectionId) {\n throw new Error(`Mutation sectionMove requires targetSectionId`);\n }\n const course = stateManager.get('course');\n this.sectionLock(stateManager, sectionIds, true);\n const updates = await this._callEditWebservice('section_move', course.id, sectionIds, targetSectionId);\n stateManager.processUpdates(updates);\n this.sectionLock(stateManager, sectionIds, false);\n }\n\n /**\n * Add a new section to a specific course location.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {number} targetSectionId optional the target section id\n */\n async addSection(stateManager, targetSectionId) {\n if (!targetSectionId) {\n targetSectionId = 0;\n }\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('section_add', course.id, [], targetSectionId);\n stateManager.processUpdates(updates);\n }\n\n /**\n * Delete sections.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} sectionIds the list of course modules ids\n */\n async sectionDelete(stateManager, sectionIds) {\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('section_delete', course.id, sectionIds);\n stateManager.processUpdates(updates);\n }\n\n /**\n * Mark or unmark course modules as dragging.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} cmIds the list of course modules ids\n * @param {bool} dragValue the new dragging value\n */\n cmDrag(stateManager, cmIds, dragValue) {\n this._setElementsValue(stateManager, 'cm', cmIds, 'dragging', dragValue);\n }\n\n /**\n * Mark or unmark course sections as dragging.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} sectionIds the list of section ids\n * @param {bool} dragValue the new dragging value\n */\n sectionDrag(stateManager, sectionIds, dragValue) {\n this._setElementsValue(stateManager, 'section', sectionIds, 'dragging', dragValue);\n }\n\n /**\n * Mark or unmark course modules as complete.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} cmIds the list of course modules ids\n * @param {bool} complete the new completion value\n */\n cmCompletion(stateManager, cmIds, complete) {\n const newValue = (complete) ? 1 : 0;\n this._setElementsValue(stateManager, 'cm', cmIds, 'completionstate', newValue);\n }\n\n /**\n * Lock or unlock course modules.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} cmIds the list of course modules ids\n * @param {bool} lockValue the new locked value\n */\n cmLock(stateManager, cmIds, lockValue) {\n this._setElementsValue(stateManager, 'cm', cmIds, 'locked', lockValue);\n }\n\n /**\n * Lock or unlock course sections.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} sectionIds the list of section ids\n * @param {bool} lockValue the new locked value\n */\n sectionLock(stateManager, sectionIds, lockValue) {\n this._setElementsValue(stateManager, 'section', sectionIds, 'locked', lockValue);\n }\n\n _setElementsValue(stateManager, name, ids, fieldName, newValue) {\n stateManager.setReadOnly(false);\n ids.forEach((id) => {\n const element = stateManager.get(name, id);\n if (element) {\n element[fieldName] = newValue;\n }\n });\n stateManager.setReadOnly(true);\n }\n\n /**\n * Unlock all course elements.\n *\n * @param {StateManager} stateManager the current state manager\n */\n unlockAll(stateManager) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n state.section.forEach((section) => {\n section.locked = false;\n });\n state.cm.forEach((cm) => {\n cm.locked = false;\n });\n stateManager.setReadOnly(true);\n }\n\n /*\n * Get updated user preferences and state data related to some section ids.\n *\n * @param {StateManager} stateManager the current state\n * @param {array} sectionIds the list of section ids to update\n * @param {Object} preferences the new preferences values\n */\n async sectionPreferences(stateManager, sectionIds, preferences) {\n stateManager.setReadOnly(false);\n // Check if we need to update preferences.\n let updatePreferences = false;\n sectionIds.forEach(sectionId => {\n const section = stateManager.get('section', sectionId);\n if (section === undefined) {\n return;\n }\n let newValue = preferences.contentcollapsed ?? section.contentcollapsed;\n if (section.contentcollapsed != newValue) {\n section.contentcollapsed = newValue;\n updatePreferences = true;\n }\n newValue = preferences.indexcollapsed ?? section.indexcollapsed;\n if (section.indexcollapsed != newValue) {\n section.indexcollapsed = newValue;\n updatePreferences = true;\n }\n });\n stateManager.setReadOnly(true);\n\n if (updatePreferences) {\n // Build the preference structures.\n const course = stateManager.get('course');\n const state = stateManager.state;\n const prefKey = `coursesectionspreferences_${course.id}`;\n const preferences = {\n contentcollapsed: [],\n indexcollapsed: [],\n };\n state.section.forEach(section => {\n if (section.contentcollapsed) {\n preferences.contentcollapsed.push(section.id);\n }\n if (section.indexcollapsed) {\n preferences.indexcollapsed.push(section.id);\n }\n });\n const jsonString = JSON.stringify(preferences);\n M.util.set_user_preference(prefKey, jsonString);\n }\n }\n\n /**\n * Get updated state data related to some cm ids.\n *\n * @method cmState\n * @param {StateManager} stateManager the current state\n * @param {array} cmids the list of cm ids to update\n */\n async cmState(stateManager, cmids) {\n this.cmLock(stateManager, cmids, true);\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('cm_state', course.id, cmids);\n stateManager.processUpdates(updates);\n this.cmLock(stateManager, cmids, false);\n }\n\n /**\n * Get updated state data related to some section ids.\n *\n * @method sectionState\n * @param {StateManager} stateManager the current state\n * @param {array} sectionIds the list of section ids to update\n */\n async sectionState(stateManager, sectionIds) {\n this.sectionLock(stateManager, sectionIds, true);\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('section_state', course.id, sectionIds);\n stateManager.processUpdates(updates);\n this.sectionLock(stateManager, sectionIds, false);\n }\n\n /**\n * Get the full updated state data of the course.\n *\n * @param {StateManager} stateManager the current state\n */\n async courseState(stateManager) {\n const course = stateManager.get('course');\n const updates = await this._callEditWebservice('course_state', course.id);\n stateManager.processUpdates(updates);\n }\n\n}\n"],"file":"mutations.min.js"} \ No newline at end of file diff --git a/course/format/amd/build/local/courseindex/courseindex.min.js b/course/format/amd/build/local/courseindex/courseindex.min.js index e5188f5145a..26cb7412422 100644 --- a/course/format/amd/build/local/courseindex/courseindex.min.js +++ b/course/format/amd/build/local/courseindex/courseindex.min.js @@ -1,2 +1,2 @@ -define ("core_courseformat/local/courseindex/courseindex",["exports","core/reactive","core_courseformat/courseeditor","jquery","core_courseformat/local/courseeditor/contenttree"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;d=f(d);e=f(e);function f(a){return a&&a.__esModule?a:{default:a}}function g(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){g=function(a){return typeof a}}else{g=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return g(a)}function h(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function i(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var i=a.apply(b,c);function f(a){h(i,d,e,f,g,"next",a)}function g(a){h(i,d,e,f,g,"throw",a)}f(void 0)})}}function j(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function k(a,b){for(var c=0,d;cb.length){a.removeChild(a.lastChild)}}},{key:"_deleteCm",value:function _deleteCm(a){var b=a.element;delete this.cms[b.id]}},{key:"_deleteSection",value:function _deleteSection(a){var b=a.element;delete this.sections[b.id]}}],[{key:"init",value:function init(a,d){return new b({element:document.getElementById(a),reactive:(0,c.getCurrentCourseEditor)(),selectors:d})}}]);return b}(b.BaseComponent);a.default=t;return a.default}); +define ("core_courseformat/local/courseindex/courseindex",["exports","core/reactive","core_courseformat/courseeditor","jquery","core_courseformat/local/courseeditor/contenttree"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;d=f(d);e=f(e);function f(a){return a&&a.__esModule?a:{default:a}}function g(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){g=function(a){return typeof a}}else{g=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return g(a)}function h(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function i(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var i=a.apply(b,c);function f(a){h(i,d,e,f,g,"next",a)}function g(a){h(i,d,e,f,g,"throw",a)}f(void 0)})}}function j(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function k(a,b){for(var c=0,d;cb.length){a.removeChild(a.lastChild)}}},{key:"_deleteCm",value:function _deleteCm(a){var b=a.element;delete this.cms[b.id]}},{key:"_deleteSection",value:function _deleteSection(a){var b=a.element;delete this.sections[b.id]}}],[{key:"init",value:function init(a,d){return new b({element:document.getElementById(a),reactive:(0,c.getCurrentCourseEditor)(),selectors:d})}}]);return b}(b.BaseComponent);a.default=t;return a.default}); //# sourceMappingURL=courseindex.min.js.map diff --git a/course/format/amd/build/local/courseindex/courseindex.min.js.map b/course/format/amd/build/local/courseindex/courseindex.min.js.map index 87e6ad17a68..65f2db9c0e6 100644 --- a/course/format/amd/build/local/courseindex/courseindex.min.js.map +++ b/course/format/amd/build/local/courseindex/courseindex.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../../src/local/courseindex/courseindex.js"],"names":["Component","name","selectors","SECTION","SECTION_CMLIST","CM","TOGGLER","COLLAPSE","DRAWER","classes","SECTIONHIDDEN","CMHIDDEN","SECTIONCURRENT","COLLAPSED","SHOW","sections","cms","addEventListener","element","_sectionTogglers","getElements","forEach","section","dataset","id","cm","contentTree","ContentTree","reactive","isEditing","watch","handler","_refreshSectionCollapsed","_createCm","_deleteCm","_createSection","_deleteSection","_refreshCourseSectionlist","_refreshSectionCmlist","event","sectionlink","target","closest","isChevron","toggler","querySelector","isCollapsed","classList","contains","sectionId","getAttribute","dispatch","isactive","getElement","Error","_expandSectionNode","forceValue","collapsibleId","replace","collapsible","document","getElementById","togglerValue","collapse","state","fakeelement","createElement","add","innerHTML","get","sectionid","exporter","getExporter","data","renderComponent","newcomponent","newelement","parentNode","replaceChild","course","cmlist","listparent","_fixOrder","sectionlist","container","neworder","allitems","length","remove","itemid","index","item","currentitem","children","append","insertBefore","removeChild","lastChild","BaseComponent"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course index main component.\n *\n * @module core_courseformat/local/courseindex/courseindex\n * @class core_courseformat/local/courseindex/courseindex\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport jQuery from 'jquery';\nimport ContentTree from 'core_courseformat/local/courseeditor/contenttree';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'courseindex';\n // Default query selectors.\n this.selectors = {\n SECTION: `[data-for='section']`,\n SECTION_CMLIST: `[data-for='cmlist']`,\n CM: `[data-for='cm']`,\n TOGGLER: `[data-action=\"togglecourseindexsection\"]`,\n COLLAPSE: `[data-toggle=\"collapse\"]`,\n DRAWER: `.drawer`,\n };\n // Default classes to toggle on refresh.\n this.classes = {\n SECTIONHIDDEN: 'dimmed',\n CMHIDDEN: 'dimmed',\n SECTIONCURRENT: 'current',\n COLLAPSED: `collapsed`,\n SHOW: `show`,\n };\n // Arrays to keep cms and sections elements.\n this.sections = {};\n this.cms = {};\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new Component({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n */\n stateReady() {\n // Activate section togglers.\n this.addEventListener(this.element, 'click', this._sectionTogglers);\n\n // Get cms and sections elements.\n const sections = this.getElements(this.selectors.SECTION);\n sections.forEach((section) => {\n this.sections[section.dataset.id] = section;\n });\n const cms = this.getElements(this.selectors.CM);\n cms.forEach((cm) => {\n this.cms[cm.dataset.id] = cm;\n });\n\n // Configure Aria Tree.\n this.contentTree = new ContentTree(this.element, this.selectors, this.reactive.isEditing);\n }\n\n getWatchers() {\n return [\n {watch: `section.isactive:updated`, handler: this._refreshSectionCollapsed},\n {watch: `cm:created`, handler: this._createCm},\n {watch: `cm:deleted`, handler: this._deleteCm},\n {watch: `section:created`, handler: this._createSection},\n {watch: `section:deleted`, handler: this._deleteSection},\n // Sections and cm sorting.\n {watch: `course.sectionlist:updated`, handler: this._refreshCourseSectionlist},\n {watch: `section.cmlist:updated`, handler: this._refreshSectionCmlist},\n ];\n }\n\n /**\n * Setup sections toggler.\n *\n * Toggler click is delegated to the main course index element because new sections can\n * appear at any moment and this way we prevent accidental double bindings.\n *\n * @param {Event} event the triggered event\n */\n _sectionTogglers(event) {\n const sectionlink = event.target.closest(this.selectors.TOGGLER);\n const isChevron = event.target.closest(this.selectors.COLLAPSE);\n\n if (sectionlink || isChevron) {\n\n const section = event.target.closest(this.selectors.SECTION);\n const toggler = section.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (isChevron || isCollapsed) {\n // Update the state.\n const sectionId = section.getAttribute('data-id');\n this.reactive.dispatch(\n 'sectionPreferences',\n [sectionId],\n {\n isactive: isCollapsed,\n },\n );\n }\n }\n }\n\n /**\n * Update section collapsed.\n *\n * @param {object} args\n * @param {object} args.element The leement to be expanded\n */\n _refreshSectionCollapsed({element}) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n if (!target) {\n throw new Error(`Unkown section with ID ${element.id}`);\n }\n // Check if it is already done.\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (element.isactive === isCollapsed) {\n this._expandSectionNode(element);\n }\n }\n\n /**\n * Expand a section node.\n *\n * By default the method will use element.isactive to decide if the\n * section is opened or closed. However, using forceValue it is possible\n * to open or close a section independant from the isactive attribute.\n *\n * @param {Object} element the course module state element\n * @param {boolean} forceValue optional forced expanded value\n */\n _expandSectionNode(element, forceValue) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n let collapsibleId = toggler.dataset.target ?? toggler.getAttribute(\"href\");\n if (!collapsibleId) {\n return;\n }\n collapsibleId = collapsibleId.replace('#', '');\n const collapsible = document.getElementById(collapsibleId);\n if (!collapsible) {\n return;\n }\n\n if (forceValue === undefined) {\n forceValue = (element.isactive) ? true : false;\n }\n\n // Course index is based on Bootstrap 4 collapsibles. To collapse them we need jQuery to\n // interact with collapsibles methods. Hopefully, this will change in Bootstrap 5 because\n // it does not require jQuery anymore (when MDL-79179 is integrated).\n const togglerValue = (forceValue) ? 'show' : 'hide';\n jQuery(collapsible).collapse(togglerValue);\n }\n\n /**\n * Create a newcm instance.\n *\n * @param {object} param\n * @param {Object} param.state\n * @param {Object} param.element\n */\n async _createCm({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('li');\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n this.cms[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshSectionCmlist({\n state,\n element: state.section.get(element.sectionid),\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.cm(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'core_courseformat/local/courseindex/cm', data);\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.cms[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n }\n\n /**\n * Create a new section instance.\n *\n * @param {Object} details the update details.\n * @param {Object} details.state the state data.\n * @param {Object} details.element the element data.\n */\n async _createSection({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('div');\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n this.sections[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshCourseSectionlist({\n state,\n element: state.course,\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.section(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'core_courseformat/local/courseindex/section', data);\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.sections[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n }\n\n /**\n * Refresh a section cm list.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _refreshSectionCmlist({element}) {\n const cmlist = element.cmlist ?? [];\n const listparent = this.getElement(this.selectors.SECTION_CMLIST, element.id);\n this._fixOrder(listparent, cmlist, this.cms);\n }\n\n /**\n * Refresh the section list.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _refreshCourseSectionlist({element}) {\n const sectionlist = element.sectionlist ?? [];\n this._fixOrder(this.element, sectionlist, this.sections);\n }\n\n /**\n * Fix/reorder the section or cms order.\n *\n * @param {Element} container the HTML element to reorder.\n * @param {Array} neworder an array with the ids order\n * @param {Array} allitems the list of html elements that can be placed in the container\n */\n _fixOrder(container, neworder, allitems) {\n\n // Empty lists should not be visible.\n if (!neworder.length) {\n container.classList.add('hidden');\n container.innerHTML = '';\n return;\n }\n\n // Grant the list is visible (in case it was empty).\n container.classList.remove('hidden');\n\n // Move the elements in order at the beginning of the list.\n neworder.forEach((itemid, index) => {\n const item = allitems[itemid];\n // Get the current element at that position.\n const currentitem = container.children[index];\n if (currentitem === undefined) {\n container.append(item);\n return;\n }\n if (currentitem !== item) {\n container.insertBefore(item, currentitem);\n }\n });\n // Remove the remaining elements.\n while (container.children.length > neworder.length) {\n container.removeChild(container.lastChild);\n }\n }\n\n /**\n * Remove a cm from the list.\n *\n * The actual DOM element removal is delegated to the cm component.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _deleteCm({element}) {\n delete this.cms[element.id];\n }\n\n /**\n * Remove a section from the list.\n *\n * The actual DOM element removal is delegated to the section component.\n *\n * @param {Object} details the update details.\n * @param {Object} details.element the element data.\n */\n _deleteSection({element}) {\n delete this.sections[element.id];\n }\n}\n"],"file":"courseindex.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/courseindex/courseindex.js"],"names":["Component","name","selectors","SECTION","SECTION_CMLIST","CM","TOGGLER","COLLAPSE","DRAWER","classes","SECTIONHIDDEN","CMHIDDEN","SECTIONCURRENT","COLLAPSED","SHOW","sections","cms","addEventListener","element","_sectionTogglers","getElements","forEach","section","dataset","id","cm","contentTree","ContentTree","reactive","isEditing","watch","handler","_refreshSectionCollapsed","_createCm","_deleteCm","_createSection","_deleteSection","_refreshCourseSectionlist","_refreshSectionCmlist","event","sectionlink","target","closest","isChevron","toggler","querySelector","isCollapsed","classList","contains","sectionId","getAttribute","dispatch","indexcollapsed","getElement","Error","_expandSectionNode","forceValue","collapsibleId","replace","collapsible","document","getElementById","togglerValue","collapse","state","fakeelement","createElement","add","innerHTML","get","sectionid","exporter","getExporter","data","renderComponent","newcomponent","newelement","parentNode","replaceChild","course","cmlist","listparent","_fixOrder","sectionlist","container","neworder","allitems","length","remove","itemid","index","item","currentitem","children","append","insertBefore","removeChild","lastChild","BaseComponent"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course index main component.\n *\n * @module core_courseformat/local/courseindex/courseindex\n * @class core_courseformat/local/courseindex/courseindex\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport jQuery from 'jquery';\nimport ContentTree from 'core_courseformat/local/courseeditor/contenttree';\n\nexport default class Component extends BaseComponent {\n\n /**\n * Constructor hook.\n */\n create() {\n // Optional component name for debugging.\n this.name = 'courseindex';\n // Default query selectors.\n this.selectors = {\n SECTION: `[data-for='section']`,\n SECTION_CMLIST: `[data-for='cmlist']`,\n CM: `[data-for='cm']`,\n TOGGLER: `[data-action=\"togglecourseindexsection\"]`,\n COLLAPSE: `[data-toggle=\"collapse\"]`,\n DRAWER: `.drawer`,\n };\n // Default classes to toggle on refresh.\n this.classes = {\n SECTIONHIDDEN: 'dimmed',\n CMHIDDEN: 'dimmed',\n SECTIONCURRENT: 'current',\n COLLAPSED: `collapsed`,\n SHOW: `show`,\n };\n // Arrays to keep cms and sections elements.\n this.sections = {};\n this.cms = {};\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {element|string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new Component({\n element: document.getElementById(target),\n reactive: getCurrentCourseEditor(),\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n */\n stateReady() {\n // Activate section togglers.\n this.addEventListener(this.element, 'click', this._sectionTogglers);\n\n // Get cms and sections elements.\n const sections = this.getElements(this.selectors.SECTION);\n sections.forEach((section) => {\n this.sections[section.dataset.id] = section;\n });\n const cms = this.getElements(this.selectors.CM);\n cms.forEach((cm) => {\n this.cms[cm.dataset.id] = cm;\n });\n\n // Configure Aria Tree.\n this.contentTree = new ContentTree(this.element, this.selectors, this.reactive.isEditing);\n }\n\n getWatchers() {\n return [\n {watch: `section.indexcollapsed:updated`, handler: this._refreshSectionCollapsed},\n {watch: `cm:created`, handler: this._createCm},\n {watch: `cm:deleted`, handler: this._deleteCm},\n {watch: `section:created`, handler: this._createSection},\n {watch: `section:deleted`, handler: this._deleteSection},\n // Sections and cm sorting.\n {watch: `course.sectionlist:updated`, handler: this._refreshCourseSectionlist},\n {watch: `section.cmlist:updated`, handler: this._refreshSectionCmlist},\n ];\n }\n\n /**\n * Setup sections toggler.\n *\n * Toggler click is delegated to the main course index element because new sections can\n * appear at any moment and this way we prevent accidental double bindings.\n *\n * @param {Event} event the triggered event\n */\n _sectionTogglers(event) {\n const sectionlink = event.target.closest(this.selectors.TOGGLER);\n const isChevron = event.target.closest(this.selectors.COLLAPSE);\n\n if (sectionlink || isChevron) {\n\n const section = event.target.closest(this.selectors.SECTION);\n const toggler = section.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (isChevron || isCollapsed) {\n // Update the state.\n const sectionId = section.getAttribute('data-id');\n this.reactive.dispatch(\n 'sectionPreferences',\n [sectionId],\n {\n indexcollapsed: !isCollapsed,\n },\n );\n }\n }\n }\n\n /**\n * Update section collapsed.\n *\n * @param {object} args\n * @param {object} args.element The leement to be expanded\n */\n _refreshSectionCollapsed({element}) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n if (!target) {\n throw new Error(`Unkown section with ID ${element.id}`);\n }\n // Check if it is already done.\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false;\n\n if (element.indexcollapsed !== isCollapsed) {\n this._expandSectionNode(element);\n }\n }\n\n /**\n * Expand a section node.\n *\n * By default the method will use element.indexcollapsed to decide if the\n * section is opened or closed. However, using forceValue it is possible\n * to open or close a section independant from the indexcollapsed attribute.\n *\n * @param {Object} element the course module state element\n * @param {boolean} forceValue optional forced expanded value\n */\n _expandSectionNode(element, forceValue) {\n const target = this.getElement(this.selectors.SECTION, element.id);\n const toggler = target.querySelector(this.selectors.COLLAPSE);\n let collapsibleId = toggler.dataset.target ?? toggler.getAttribute(\"href\");\n if (!collapsibleId) {\n return;\n }\n collapsibleId = collapsibleId.replace('#', '');\n const collapsible = document.getElementById(collapsibleId);\n if (!collapsible) {\n return;\n }\n\n if (forceValue === undefined) {\n forceValue = (element.indexcollapsed) ? false : true;\n }\n\n // Course index is based on Bootstrap 4 collapsibles. To collapse them we need jQuery to\n // interact with collapsibles methods. Hopefully, this will change in Bootstrap 5 because\n // it does not require jQuery anymore (when MDL-79179 is integrated).\n const togglerValue = (forceValue) ? 'show' : 'hide';\n jQuery(collapsible).collapse(togglerValue);\n }\n\n /**\n * Create a newcm instance.\n *\n * @param {object} param\n * @param {Object} param.state\n * @param {Object} param.element\n */\n async _createCm({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('li');\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n this.cms[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshSectionCmlist({\n state,\n element: state.section.get(element.sectionid),\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.cm(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'core_courseformat/local/courseindex/cm', data);\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.cms[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n }\n\n /**\n * Create a new section instance.\n *\n * @param {Object} details the update details.\n * @param {Object} details.state the state data.\n * @param {Object} details.element the element data.\n */\n async _createSection({state, element}) {\n // Create a fake node while the component is loading.\n const fakeelement = document.createElement('div');\n fakeelement.classList.add('bg-pulse-grey', 'w-100');\n fakeelement.innerHTML = ' ';\n this.sections[element.id] = fakeelement;\n // Place the fake node on the correct position.\n this._refreshCourseSectionlist({\n state,\n element: state.course,\n });\n // Collect render data.\n const exporter = this.reactive.getExporter();\n const data = exporter.section(state, element);\n // Create the new content.\n const newcomponent = await this.renderComponent(fakeelement, 'core_courseformat/local/courseindex/section', data);\n // Replace the fake node with the real content.\n const newelement = newcomponent.getElement();\n this.sections[element.id] = newelement;\n fakeelement.parentNode.replaceChild(newelement, fakeelement);\n }\n\n /**\n * Refresh a section cm list.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _refreshSectionCmlist({element}) {\n const cmlist = element.cmlist ?? [];\n const listparent = this.getElement(this.selectors.SECTION_CMLIST, element.id);\n this._fixOrder(listparent, cmlist, this.cms);\n }\n\n /**\n * Refresh the section list.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _refreshCourseSectionlist({element}) {\n const sectionlist = element.sectionlist ?? [];\n this._fixOrder(this.element, sectionlist, this.sections);\n }\n\n /**\n * Fix/reorder the section or cms order.\n *\n * @param {Element} container the HTML element to reorder.\n * @param {Array} neworder an array with the ids order\n * @param {Array} allitems the list of html elements that can be placed in the container\n */\n _fixOrder(container, neworder, allitems) {\n\n // Empty lists should not be visible.\n if (!neworder.length) {\n container.classList.add('hidden');\n container.innerHTML = '';\n return;\n }\n\n // Grant the list is visible (in case it was empty).\n container.classList.remove('hidden');\n\n // Move the elements in order at the beginning of the list.\n neworder.forEach((itemid, index) => {\n const item = allitems[itemid];\n // Get the current element at that position.\n const currentitem = container.children[index];\n if (currentitem === undefined) {\n container.append(item);\n return;\n }\n if (currentitem !== item) {\n container.insertBefore(item, currentitem);\n }\n });\n // Remove the remaining elements.\n while (container.children.length > neworder.length) {\n container.removeChild(container.lastChild);\n }\n }\n\n /**\n * Remove a cm from the list.\n *\n * The actual DOM element removal is delegated to the cm component.\n *\n * @param {object} param\n * @param {Object} param.element\n */\n _deleteCm({element}) {\n delete this.cms[element.id];\n }\n\n /**\n * Remove a section from the list.\n *\n * The actual DOM element removal is delegated to the section component.\n *\n * @param {Object} details the update details.\n * @param {Object} details.element the element data.\n */\n _deleteSection({element}) {\n delete this.sections[element.id];\n }\n}\n"],"file":"courseindex.min.js"} \ No newline at end of file diff --git a/course/format/amd/src/local/content.js b/course/format/amd/src/local/content.js index 47046c8355e..f6d055cc656 100644 --- a/course/format/amd/src/local/content.js +++ b/course/format/amd/src/local/content.js @@ -151,7 +151,7 @@ export default class Component extends BaseComponent { 'sectionPreferences', [sectionId], { - contentexpanded: isCollapsed, + contentcollapsed: !isCollapsed, }, ); } @@ -177,7 +177,7 @@ export default class Component extends BaseComponent { 'sectionPreferences', course.sectionlist ?? [], { - contentexpanded: isAllCollapsed, + contentcollapsed: !isAllCollapsed, } ); } @@ -202,7 +202,7 @@ export default class Component extends BaseComponent { // Update section number and title. {watch: `section.number:updated`, handler: this._refreshSectionNumber}, // Collapse and expand sections. - {watch: `section.contentexpanded:updated`, handler: this._refreshSectionCollapsed}, + {watch: `section.contentcollapsed:updated`, handler: this._refreshSectionCollapsed}, // Sections and cm sorting. {watch: `transaction:start`, handler: this._startProcessing}, {watch: `course.sectionlist:updated`, handler: this._refreshCourseSectionlist}, @@ -231,7 +231,7 @@ export default class Component extends BaseComponent { const toggler = target.querySelector(this.selectors.COLLAPSE); const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false; - if (element.contentexpanded === isCollapsed) { + if (element.contentcollapsed !== isCollapsed) { toggler.click(); } @@ -253,8 +253,8 @@ export default class Component extends BaseComponent { let allexpanded = true; state.section.forEach( section => { - allcollapsed = allcollapsed && !section.contentexpanded; - allexpanded = allexpanded && section.contentexpanded; + allcollapsed = allcollapsed && section.contentcollapsed; + allexpanded = allexpanded && !section.contentcollapsed; } ); if (allcollapsed) { diff --git a/course/format/amd/src/local/courseeditor/mutations.js b/course/format/amd/src/local/courseeditor/mutations.js index 2905709df22..988d4088986 100644 --- a/course/format/amd/src/local/courseeditor/mutations.js +++ b/course/format/amd/src/local/courseeditor/mutations.js @@ -258,14 +258,14 @@ export default class { if (section === undefined) { return; } - let newValue = preferences.contentexpanded ?? section.contentexpanded; - if (section.contentexpanded != newValue) { - section.contentexpanded = newValue; + let newValue = preferences.contentcollapsed ?? section.contentcollapsed; + if (section.contentcollapsed != newValue) { + section.contentcollapsed = newValue; updatePreferences = true; } - newValue = preferences.isactive ?? section.isactive; - if (section.isactive != newValue) { - section.isactive = newValue; + newValue = preferences.indexcollapsed ?? section.indexcollapsed; + if (section.indexcollapsed != newValue) { + section.indexcollapsed = newValue; updatePreferences = true; } }); @@ -281,10 +281,10 @@ export default class { indexcollapsed: [], }; state.section.forEach(section => { - if (!section.contentexpanded) { + if (section.contentcollapsed) { preferences.contentcollapsed.push(section.id); } - if (!section.isactive) { + if (section.indexcollapsed) { preferences.indexcollapsed.push(section.id); } }); diff --git a/course/format/amd/src/local/courseindex/courseindex.js b/course/format/amd/src/local/courseindex/courseindex.js index c562034cd17..54f181af73f 100644 --- a/course/format/amd/src/local/courseindex/courseindex.js +++ b/course/format/amd/src/local/courseindex/courseindex.js @@ -95,7 +95,7 @@ export default class Component extends BaseComponent { getWatchers() { return [ - {watch: `section.isactive:updated`, handler: this._refreshSectionCollapsed}, + {watch: `section.indexcollapsed:updated`, handler: this._refreshSectionCollapsed}, {watch: `cm:created`, handler: this._createCm}, {watch: `cm:deleted`, handler: this._deleteCm}, {watch: `section:created`, handler: this._createSection}, @@ -131,7 +131,7 @@ export default class Component extends BaseComponent { 'sectionPreferences', [sectionId], { - isactive: isCollapsed, + indexcollapsed: !isCollapsed, }, ); } @@ -153,7 +153,7 @@ export default class Component extends BaseComponent { const toggler = target.querySelector(this.selectors.COLLAPSE); const isCollapsed = toggler?.classList.contains(this.classes.COLLAPSED) ?? false; - if (element.isactive === isCollapsed) { + if (element.indexcollapsed !== isCollapsed) { this._expandSectionNode(element); } } @@ -161,9 +161,9 @@ export default class Component extends BaseComponent { /** * Expand a section node. * - * By default the method will use element.isactive to decide if the + * By default the method will use element.indexcollapsed to decide if the * section is opened or closed. However, using forceValue it is possible - * to open or close a section independant from the isactive attribute. + * to open or close a section independant from the indexcollapsed attribute. * * @param {Object} element the course module state element * @param {boolean} forceValue optional forced expanded value @@ -182,7 +182,7 @@ export default class Component extends BaseComponent { } if (forceValue === undefined) { - forceValue = (element.isactive) ? true : false; + forceValue = (element.indexcollapsed) ? false : true; } // Course index is based on Bootstrap 4 collapsibles. To collapse them we need jQuery to diff --git a/course/format/classes/output/local/content/section.php b/course/format/classes/output/local/content/section.php index fba709c7e2b..2995223ad41 100644 --- a/course/format/classes/output/local/content/section.php +++ b/course/format/classes/output/local/content/section.php @@ -168,12 +168,12 @@ class section implements renderable, templatable { $data->sitehome = true; } - $data->contentexpanded = true; + $data->contentcollapsed = false; $preferences = $format->get_sections_preferences(); if (isset($preferences[$thissection->id])) { $sectionpreferences = $preferences[$thissection->id]; if (!empty($sectionpreferences->contentcollapsed)) { - $data->contentexpanded = false; + $data->contentcollapsed = true; } } diff --git a/course/format/classes/output/local/state/section.php b/course/format/classes/output/local/state/section.php index 82438df970b..232720c2c6c 100644 --- a/course/format/classes/output/local/state/section.php +++ b/course/format/classes/output/local/state/section.php @@ -62,16 +62,16 @@ class section implements renderable { $section = $this->section; $modinfo = $format->get_modinfo(); - $isactive = true; - $contentexpanded = true; + $indexcollapsed = false; + $contentcollapsed = false; $preferences = $format->get_sections_preferences(); if (isset($preferences[$section->id])) { $sectionpreferences = $preferences[$section->id]; if (!empty($sectionpreferences->contentcollapsed)) { - $contentexpanded = false; + $contentcollapsed = true; } if (!empty($sectionpreferences->indexcollapsed)) { - $isactive = false; + $indexcollapsed = true; } } @@ -86,8 +86,8 @@ class section implements renderable { 'visible' => !empty($section->visible), 'sectionurl' => course_get_url($course, $section->section)->out(), 'current' => $format->is_section_current($section), - 'isactive' => $isactive, - 'contentexpanded' => $contentexpanded + 'indexcollapsed' => $indexcollapsed, + 'contentcollapsed' => $contentcollapsed ]; // If the section availability restrictions must be displayed. diff --git a/course/format/templates/local/content/movesection.mustache b/course/format/templates/local/content/movesection.mustache index 3c3e944a0fd..039e91e2803 100644 --- a/course/format/templates/local/content/movesection.mustache +++ b/course/format/templates/local/content/movesection.mustache @@ -29,14 +29,14 @@ "id": 42, "number": 1, "sectionurl": "#", - "isactive": 1 + "indexcollapsed": 0 }, { "title": "City of God or Cidade de Deus", "id": "43", "number": "2", "sectionurl": "#", - "isactive": 0 + "indexcollapsed": 1 } ] } diff --git a/course/format/templates/local/content/section.mustache b/course/format/templates/local/content/section.mustache index a8251f85de8..889b11f627f 100644 --- a/course/format/templates/local/content/section.mustache +++ b/course/format/templates/local/content/section.mustache @@ -73,7 +73,7 @@ "cmcontrols": "[Add an activity or resource]", "iscoursedisplaymultipage": true, "sectionreturnid": 0, - "contentexpanded": true, + "contentcollapsed": false, "insertafter": true, "numsections": 42, "sitehome": false @@ -125,7 +125,7 @@
{{#summary}} diff --git a/course/format/templates/local/content/section/header.mustache b/course/format/templates/local/content/section/header.mustache index d5536b2a17a..eb630a99cf3 100644 --- a/course/format/templates/local/content/section/header.mustache +++ b/course/format/templates/local/content/section/header.mustache @@ -46,9 +46,11 @@ {{#pix}} t/expandedchevron, core {{/pix}} diff --git a/course/format/templates/local/courseindex/cm.mustache b/course/format/templates/local/courseindex/cm.mustache index bb4314dd2b7..1d2dbc547b8 100644 --- a/course/format/templates/local/courseindex/cm.mustache +++ b/course/format/templates/local/courseindex/cm.mustache @@ -27,7 +27,6 @@ "visible": 1, "isactive": 1, "uniqid": "0", - "isactive": 1, "accessvisible": 1, "hascmrectrictions": 0 } diff --git a/course/format/templates/local/courseindex/courseindex.mustache b/course/format/templates/local/courseindex/courseindex.mustache index 7965892b401..8cc35d1688d 100644 --- a/course/format/templates/local/courseindex/courseindex.mustache +++ b/course/format/templates/local/courseindex/courseindex.mustache @@ -28,7 +28,7 @@ "id": 42, "number": 1, "sectionurl": "#", - "isactive": 1, + "indexcollapsed": 0, "cms": [ { "name": "Glossary of characters", @@ -64,7 +64,7 @@ "id": "43", "number": "2", "sectionurl": "#", - "isactive": 0, + "indexcollapsed": 1, "cms": [ { "name": "Resources", diff --git a/course/format/templates/local/courseindex/section.mustache b/course/format/templates/local/courseindex/section.mustache index 59f159b635f..1b6e02e2b18 100644 --- a/course/format/templates/local/courseindex/section.mustache +++ b/course/format/templates/local/courseindex/section.mustache @@ -26,7 +26,7 @@ "uniqid": "0", "number": 1, "sectionurl": "#", - "isactive": 1, + "indexcollapsed": 0, "current": 1, "visible": 1, "hasrectrictions": 0, @@ -73,8 +73,8 @@ > @@ -106,7 +106,7 @@ {{#pix}}i/dragdrop{{/pix}}