MDL-71228 course: sorting course on section state change
[moodle.git] / course / format / amd / build / local / content.min.js.map
blob4aaa1c859f7e31f2a25fd4d5c88ba417b386b200
1 {"version":3,"sources":["../../src/local/content.js"],"names":["Component","name","selectors","SECTION","SECTION_ITEM","SECTION_TITLE","SECTION_CMLIST","COURSE_SECTIONLIST","CM","dettachedCms","dettachedSections","reactive","supportComponents","watch","handler","_reloadCm","_refreshSectionNumber","_startProcessing","_refreshCourseSectionlist","_refreshSectionCmlist","element","cmitem","getElement","id","courseActions","refreshModule","target","Error","number","dataset","sectionid","inplace","inplaceeditable","getInplaceEditable","querySelector","currentvalue","getValue","currentitemid","getItemId","rawtitle","setValue","cmlist","section","listparent","_fixOrder","sectionlist","container","neworder","selector","dettachedelements","length","classList","add","innerHTML","remove","forEach","itemid","index","item","currentitem","children","append","insertBefore","lastchild","lastChild","removeChild","document","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 <http://www.gnu.org/licenses/>.\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 <ferran@moodle.com>\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';\n// Course actions is needed for actions that are not migrated to components.\nimport courseActions from 'core_course/actions';\n\nexport default class Component extends BaseComponent {\n\n    /**\n     * Constructor hook.\n     */\n    create() {\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_item']`,\n            SECTION_TITLE: `[data-for='section_title']`,\n            SECTION_CMLIST: `[data-for='cmlist']`,\n            COURSE_SECTIONLIST: `[data-for='course_sectionlist']`,\n            CM: `[data-for='cmitem']`,\n        };\n        // Array to save dettached elements during element resorting.\n        this.dettachedCms = {};\n        this.dettachedSections = {};\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     * @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     * Return the component watchers.\n     *\n     * @returns {Array} of watchers\n     */\n    getWatchers() {\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            // 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        ];\n    }\n\n    /**\n     * Reload a course module.\n     *\n     * Most course module HTML is still strongly backend dependant.\n     * Some changes require to get a new version af the module.\n     *\n     * @param {Object} update the state update data\n     */\n    _reloadCm({element}) {\n        const cmitem = this.getElement(this.selectors.CM, element.id);\n        if (cmitem) {\n            courseActions.refreshModule(cmitem, element.id);\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     * 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} 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            throw new Error(`Unkown section with ID ${element.id}`);\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_TITLE));\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} 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        if (listparent) {\n            this._fixOrder(listparent, cmlist, this.selectors.CM, this.dettachedCms);\n        }\n    }\n\n    /**\n     * Refresh the section list.\n     *\n     * @param {Object} details the update details.\n     */\n    _refreshCourseSectionlist({element}) {\n        const sectionlist = element.sectionlist ?? [];\n        const listparent = this.getElement(this.selectors.COURSE_SECTIONLIST);\n        if (listparent) {\n            this._fixOrder(listparent, sectionlist, this.selectors.SECTION, this.dettachedSections);\n        }\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     */\n    _fixOrder(container, neworder, selector, dettachedelements) {\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 = this.getElement(selector, itemid) ?? dettachedelements[itemid];\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        // Remove the remaining elements.\n        while (container.children.length > neworder.length) {\n            const lastchild = container.lastChild;\n            dettachedelements[lastchild?.dataset?.id ?? 0] = lastchild;\n            container.removeChild(lastchild);\n        }\n    }\n}\n"],"file":"content.min.js"}