HEX
Server: LiteSpeed
System: Linux server.zepintelhosting.com 4.18.0 #1 SMP Mon Sep 30 15:36:27 MSK 2024 x86_64
User: enamadmin (1026)
PHP: 8.2.30
Disabled: exec,system,passthru,shell_exec,proc_open,popen,apache_child_terminate
Upload Files
File: /home/enamadmin/public_html/aaelearningb/course/format/amd/build/local/content/actions.min.js.map
{"version":3,"file":"actions.min.js","sources":["../../../src/local/content/actions.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Course state actions dispatcher.\n *\n * This module captures all data-dispatch links in the course content and dispatch the proper\n * state mutation, including any confirmation and modal required.\n *\n * @module     core_courseformat/local/content/actions\n * @class      core_courseformat/local/content/actions\n * @copyright  2021 Ferran Recio <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 Modal from 'core/modal';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport ModalDeleteCancel from 'core/modal_delete_cancel';\nimport ModalEvents from 'core/modal_events';\nimport Templates from 'core/templates';\nimport {prefetchStrings} from 'core/prefetch';\nimport {getString} from 'core/str';\nimport {getFirst} from 'core/normalise';\nimport {toggleBulkSelectionAction} from 'core_courseformat/local/content/actions/bulkselection';\nimport * as CourseEvents from 'core_course/events';\nimport Pending from 'core/pending';\nimport ContentTree from 'core_courseformat/local/courseeditor/contenttree';\n// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated.\nimport jQuery from 'jquery';\nimport Notification from \"core/notification\";\n\n// Load global strings.\nprefetchStrings('core', ['movecoursesection', 'movecoursemodule', 'confirm', 'delete']);\n\n// Mutations are dispatched by the course content actions.\n// Formats can use this module addActions static method to add custom actions.\n// Direct mutations can be simple strings (mutation) name or functions.\nconst directMutations = {\n    sectionHide: 'sectionHide',\n    sectionShow: 'sectionShow',\n    cmHide: 'cmHide',\n    cmShow: 'cmShow',\n    cmStealth: 'cmStealth',\n    cmMoveRight: 'cmMoveRight',\n    cmMoveLeft: 'cmMoveLeft',\n    cmNoGroups: 'cmNoGroups',\n    cmSeparateGroups: 'cmSeparateGroups',\n    cmVisibleGroups: 'cmVisibleGroups',\n};\n\nexport default class extends BaseComponent {\n\n    /**\n     * Constructor hook.\n     */\n    create() {\n        // Optional component name for debugging.\n        this.name = 'content_actions';\n        // Default query selectors.\n        this.selectors = {\n            ACTIONLINK: `[data-action]`,\n            // Move modal selectors.\n            SECTIONLINK: `[data-for='section']`,\n            CMLINK: `[data-for='cm']`,\n            SECTIONNODE: `[data-for='sectionnode']`,\n            MODALTOGGLER: `[data-toggle='collapse']`,\n            ADDSECTION: `[data-action='addSection']`,\n            CONTENTTREE: `#destination-selector`,\n            ACTIONMENU: `.action-menu`,\n            ACTIONMENUTOGGLER: `[data-toggle=\"dropdown\"]`,\n            // Availability modal selectors.\n            OPTIONSRADIO: `[type='radio']`,\n            COURSEADDSECTION: `#course-addsection`,\n            MAXSECTIONSWARNING: `[data-region='max-sections-warning']`,\n            ADDSECTIONREGION: `[data-region='section-addsection']`,\n        };\n        // Component css classes.\n        this.classes = {\n            DISABLED: `disabled`,\n            ITALIC: `font-italic`,\n            DISPLAYNONE: `d-none`,\n        };\n    }\n\n    /**\n     * Add extra actions to the module.\n     *\n     * @param {array} actions array of methods to execute\n     */\n    static addActions(actions) {\n        for (const [action, mutationReference] of Object.entries(actions)) {\n            if (typeof mutationReference !== 'function' && typeof mutationReference !== 'string') {\n                throw new Error(`${action} action must be a mutation name or a function`);\n            }\n            directMutations[action] = mutationReference;\n        }\n    }\n\n    /**\n     * Initial state ready method.\n     *\n     * @param {Object} state the state data.\n     *\n     */\n    stateReady(state) {\n        // Delegate dispatch clicks.\n        this.addEventListener(\n            this.element,\n            'click',\n            this._dispatchClick\n        );\n        // Check section limit.\n        this._checkSectionlist({state});\n        // Add an Event listener to recalculate limits it if a section HTML is altered.\n        this.addEventListener(\n            this.element,\n            CourseEvents.sectionRefreshed,\n            () => this._checkSectionlist({state})\n        );\n    }\n\n    /**\n     * Return the component watchers.\n     *\n     * @returns {Array} of watchers\n     */\n    getWatchers() {\n        return [\n            // Check section limit.\n            {watch: `course.sectionlist:updated`, handler: this._checkSectionlist},\n        ];\n    }\n\n    _dispatchClick(event) {\n        const target = event.target.closest(this.selectors.ACTIONLINK);\n        if (!target) {\n            return;\n        }\n        if (target.classList.contains(this.classes.DISABLED)) {\n            event.preventDefault();\n            return;\n        }\n\n        // Invoke proper method.\n        const actionName = target.dataset.action;\n        const methodName = this._actionMethodName(actionName);\n\n        if (this[methodName] !== undefined) {\n            this[methodName](target, event);\n            return;\n        }\n\n        // Check direct mutations or mutations handlers.\n        if (directMutations[actionName] !== undefined) {\n            if (typeof directMutations[actionName] === 'function') {\n                directMutations[actionName](target, event);\n                return;\n            }\n            this._requestMutationAction(target, event, directMutations[actionName]);\n            return;\n        }\n    }\n\n    _actionMethodName(name) {\n        const requestName = name.charAt(0).toUpperCase() + name.slice(1);\n        return `_request${requestName}`;\n    }\n\n    /**\n     * Check the section list and disable some options if needed.\n     *\n     * @param {Object} detail the update details.\n     * @param {Object} detail.state the state object.\n     */\n    _checkSectionlist({state}) {\n        // Disable \"add section\" actions if the course max sections has been exceeded.\n        this._setAddSectionLocked(state.course.sectionlist.length > state.course.maxsections);\n    }\n\n    /**\n     * Return the ids represented by this element.\n     *\n     * Depending on the dataset attributes the action could represent a single id\n     * or a bulk actions with all the current selected ids.\n     *\n     * @param {HTMLElement} target\n     * @returns {Number[]} array of Ids\n     */\n    _getTargetIds(target) {\n        let ids = [];\n        if (target?.dataset?.id) {\n            ids.push(target.dataset.id);\n        }\n        const bulkType = target?.dataset?.bulk;\n        if (!bulkType) {\n            return ids;\n        }\n        const bulk = this.reactive.get('bulk');\n        if (bulk.enabled && bulk.selectedType === bulkType) {\n            ids = [...ids, ...bulk.selection];\n        }\n        return ids;\n    }\n\n    /**\n     * Handle a move section request.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     */\n    async _requestMoveSection(target, event) {\n        // Check we have an id.\n        const sectionIds = this._getTargetIds(target);\n        if (sectionIds.length == 0) {\n            return;\n        }\n\n        event.preventDefault();\n\n        const pendingModalReady = new Pending(`courseformat/actions:prepareMoveSectionModal`);\n\n        // The section edit menu to refocus on end.\n        const editTools = this._getClosestActionMenuToogler(target);\n\n        // Collect section information from the state.\n        const exporter = this.reactive.getExporter();\n        const data = exporter.course(this.reactive.state);\n        let titleText = null;\n\n        // Add the target section id and title.\n        let sectionInfo = null;\n        if (sectionIds.length == 1) {\n            sectionInfo = this.reactive.get('section', sectionIds[0]);\n            data.sectionid = sectionInfo.id;\n            data.sectiontitle = sectionInfo.title;\n            data.information = await this.reactive.getFormatString('sectionmove_info', data.sectiontitle);\n            titleText = this.reactive.getFormatString('sectionmove_title');\n        } else {\n            data.information = await this.reactive.getFormatString('sectionsmove_info', sectionIds.length);\n            titleText = this.reactive.getFormatString('sectionsmove_title');\n        }\n\n\n        // Create the modal.\n        // Build the modal parameters from the event data.\n        const modal = await this._modalBodyRenderedPromise(Modal, {\n            title: titleText,\n            body: Templates.render('core_courseformat/local/content/movesection', data),\n        });\n\n        const modalBody = getFirst(modal.getBody());\n\n        // Disable current selected section ids.\n        sectionIds.forEach(sectionId => {\n            const currentElement = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-id='${sectionId}']`);\n            this._disableLink(currentElement);\n        });\n\n        // Setup keyboard navigation.\n        new ContentTree(\n            modalBody.querySelector(this.selectors.CONTENTTREE),\n            {\n                SECTION: this.selectors.SECTIONNODE,\n                TOGGLER: this.selectors.MODALTOGGLER,\n                COLLAPSE: this.selectors.MODALTOGGLER,\n            },\n            true\n        );\n\n        // Capture click.\n        modalBody.addEventListener('click', (event) => {\n            const target = event.target;\n            if (!target.matches('a') || target.dataset.for != 'section' || target.dataset.id === undefined) {\n                return;\n            }\n            if (target.getAttribute('aria-disabled')) {\n                return;\n            }\n            event.preventDefault();\n            this.reactive.dispatch('sectionMoveAfter', sectionIds, target.dataset.id);\n            this._destroyModal(modal, editTools);\n        });\n\n        pendingModalReady.resolve();\n    }\n\n    /**\n     * Handle a move cm request.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     */\n    async _requestMoveCm(target, event) {\n        // Check we have an id.\n        const cmIds = this._getTargetIds(target);\n        if (cmIds.length == 0) {\n            return;\n        }\n\n        event.preventDefault();\n\n        const pendingModalReady = new Pending(`courseformat/actions:prepareMoveCmModal`);\n\n        // The section edit menu to refocus on end.\n        const editTools = this._getClosestActionMenuToogler(target);\n\n        // Collect information from the state.\n        const exporter = this.reactive.getExporter();\n        const data = exporter.course(this.reactive.state);\n\n        let titleText = null;\n        if (cmIds.length == 1) {\n            const cmInfo = this.reactive.get('cm', cmIds[0]);\n            data.cmid = cmInfo.id;\n            data.cmname = cmInfo.name;\n            data.information = await this.reactive.getFormatString('cmmove_info', data.cmname);\n            if (cmInfo.hasdelegatedsection) {\n                titleText = this.reactive.getFormatString('cmmove_subsectiontitle');\n            } else {\n                titleText = this.reactive.getFormatString('cmmove_title');\n            }\n        } else {\n            data.information = await this.reactive.getFormatString('cmsmove_info', cmIds.length);\n            titleText = this.reactive.getFormatString('cmsmove_title');\n        }\n\n        // Create the modal.\n        // Build the modal parameters from the event data.\n        const modal = await this._modalBodyRenderedPromise(Modal, {\n            title: titleText,\n            body: Templates.render('core_courseformat/local/content/movecm', data),\n        });\n\n        const modalBody = getFirst(modal.getBody());\n\n        // Disable current selected section ids.\n        cmIds.forEach(cmId => {\n            const currentElement = modalBody.querySelector(`${this.selectors.CMLINK}[data-id='${cmId}']`);\n            this._disableLink(currentElement);\n        });\n\n        // Setup keyboard navigation.\n        new ContentTree(\n            modalBody.querySelector(this.selectors.CONTENTTREE),\n            {\n                SECTION: this.selectors.SECTIONNODE,\n                TOGGLER: this.selectors.MODALTOGGLER,\n                COLLAPSE: this.selectors.MODALTOGGLER,\n                ENTER: this.selectors.SECTIONLINK,\n            }\n        );\n\n        // Open the cm section node if possible (Bootstrap 4 uses jQuery to interact with collapsibles).\n        // All jQuery in this code can be replaced when MDL-71979 is integrated.\n        cmIds.forEach(cmId => {\n            const cmInfo = this.reactive.get('cm', cmId);\n            let selector;\n            if (!cmInfo.hasdelegatedsection) {\n                selector = `${this.selectors.CMLINK}[data-id='${cmId}']`;\n            } else {\n                selector = `${this.selectors.SECTIONLINK}[data-id='${cmInfo.sectionid}']`;\n            }\n            const currentElement = modalBody.querySelector(selector);\n            this._expandCmMoveModalParentSections(modalBody, currentElement);\n        });\n\n        modalBody.addEventListener('click', (event) => {\n            const target = event.target;\n            if (!target.matches('a') || target.dataset.for === undefined || target.dataset.id === undefined) {\n                return;\n            }\n            if (target.getAttribute('aria-disabled')) {\n                return;\n            }\n            event.preventDefault();\n\n            let targetSectionId;\n            let targetCmId;\n            let droppedCmIds = [...cmIds];\n            if (target.dataset.for == 'cm') {\n                const dropData = exporter.cmDraggableData(this.reactive.state, target.dataset.id);\n                targetSectionId = dropData.sectionid;\n                targetCmId = dropData.nextcmid;\n            } else {\n                const section = this.reactive.get('section', target.dataset.id);\n                targetSectionId = target.dataset.id;\n                targetCmId = section?.cmlist[0];\n            }\n            const section = this.reactive.get('section', targetSectionId);\n            if (section.component) {\n                // Remove cmIds which are not allowed to be moved to this delegated section (mostly\n                // all other delegated cm).\n                droppedCmIds = droppedCmIds.filter(cmId => {\n                    const cmInfo = this.reactive.get('cm', cmId);\n                    return !cmInfo.hasdelegatedsection;\n                });\n            }\n            if (droppedCmIds.length === 0) {\n                return; // No cm to move.\n            }\n            this.reactive.dispatch('cmMove', droppedCmIds, targetSectionId, targetCmId);\n            this._destroyModal(modal, editTools);\n        });\n\n        pendingModalReady.resolve();\n    }\n\n    /**\n     * Expand all the modal tree branches that contains the element.\n     *\n     * Bootstrap 4 uses jQuery to interact with collapsibles.\n     * All jQuery in this code can be replaced when MDL-71979 is integrated.\n     *\n     * @private\n     * @param {HTMLElement} modalBody the modal body element\n     * @param {HTMLElement} element the element to display\n     */\n    _expandCmMoveModalParentSections(modalBody, element) {\n        const sectionnode = element.closest(this.selectors.SECTIONNODE);\n        if (!sectionnode) {\n            return;\n        }\n\n        const toggler = jQuery(sectionnode).find(this.selectors.MODALTOGGLER);\n        let collapsibleId = toggler.data('target') ?? toggler.attr('href');\n        if (collapsibleId) {\n            // We cannot be sure we have # in the id element name.\n            collapsibleId = collapsibleId.replace('#', '');\n            const expandNode = modalBody.querySelector(`#${collapsibleId}`);\n            jQuery(expandNode).collapse('show');\n        }\n\n        // Section are a tree structure, we need to expand all the parents.\n        this._expandCmMoveModalParentSections(modalBody, sectionnode.parentElement);\n    }\n\n    /**\n     * Handle a create section request.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     */\n    async _requestAddSection(target, event) {\n        event.preventDefault();\n        this.reactive.dispatch('addSection', target.dataset.id ?? 0);\n    }\n\n    /**\n     * Handle a create subsection request.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     */\n    async _requestAddModule(target, event) {\n        event.preventDefault();\n        this.reactive.dispatch('addModule', target.dataset.modname, target.dataset.sectionnum, target.dataset.beforemod);\n    }\n\n    /**\n     * Handle a delete section request.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     */\n    async _requestDeleteSection(target, event) {\n        const sectionIds = this._getTargetIds(target);\n        if (sectionIds.length == 0) {\n            return;\n        }\n\n        event.preventDefault();\n\n        // We don't need confirmation to delete empty sections.\n        let needsConfirmation = sectionIds.some(sectionId => {\n            const sectionInfo = this.reactive.get('section', sectionId);\n            const cmList = sectionInfo.cmlist ?? [];\n            return (cmList.length || sectionInfo.hassummary || sectionInfo.rawtitle);\n        });\n        if (!needsConfirmation) {\n            this._dispatchSectionDelete(sectionIds, target);\n            return;\n        }\n\n        let bodyText = null;\n        let titleText = null;\n        if (sectionIds.length == 1) {\n            titleText = this.reactive.getFormatString('sectiondelete_title');\n            const sectionInfo = this.reactive.get('section', sectionIds[0]);\n            bodyText = this.reactive.getFormatString('sectiondelete_info', {name: sectionInfo.title});\n        } else {\n            titleText = this.reactive.getFormatString('sectionsdelete_title');\n            bodyText = this.reactive.getFormatString('sectionsdelete_info', {count: sectionIds.length});\n        }\n\n        const modal = await this._modalBodyRenderedPromise(ModalDeleteCancel, {\n            title: titleText,\n            body: bodyText,\n        });\n\n        modal.getRoot().on(\n            ModalEvents.delete,\n            e => {\n                // Stop the default save button behaviour which is to close the modal.\n                e.preventDefault();\n                modal.destroy();\n                this._dispatchSectionDelete(sectionIds, target);\n            }\n        );\n    }\n\n    /**\n     * Dispatch the section delete action and handle the redirection if necessary.\n     *\n     * @param {Array} sectionIds  the IDs of the sections to delete.\n     * @param {Element} target the dispatch action element\n     */\n    async _dispatchSectionDelete(sectionIds, target) {\n        await this.reactive.dispatch('sectionDelete', sectionIds);\n        if (target.baseURI.includes('section.php')) {\n            // Redirect to the course main page if the section is the current page.\n            window.location.href = this.reactive.get('course').baseurl;\n        }\n    }\n\n    /**\n     * Handle a toggle cm selection.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     */\n    async _requestToggleSelectionCm(target, event) {\n        toggleBulkSelectionAction(this.reactive, target, event, 'cm');\n    }\n\n    /**\n     * Handle a toggle section selection.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     */\n    async _requestToggleSelectionSection(target, event) {\n        toggleBulkSelectionAction(this.reactive, target, event, 'section');\n    }\n\n    /**\n     * Basic mutation action helper.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     * @param {string} mutationName the mutation name\n     */\n    async _requestMutationAction(target, event, mutationName) {\n        if (!target.dataset.id && target.dataset.for !== 'bulkaction') {\n            return;\n        }\n        event.preventDefault();\n        if (target.dataset.for === 'bulkaction') {\n            // If the mutation is a bulk action we use the current selection.\n            this.reactive.dispatch(mutationName, this.reactive.get('bulk').selection);\n        } else {\n            this.reactive.dispatch(mutationName, [target.dataset.id]);\n        }\n    }\n\n    /**\n     * Handle a course module duplicate request.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     */\n    async _requestCmDuplicate(target, event) {\n        const cmIds = this._getTargetIds(target);\n        if (cmIds.length == 0) {\n            return;\n        }\n        const sectionId = target.dataset.sectionid ?? null;\n        event.preventDefault();\n        this.reactive.dispatch('cmDuplicate', cmIds, sectionId);\n    }\n\n    /**\n     * Handle a delete cm request.\n     *\n     * @param {Element} target the dispatch action element\n     * @param {Event} event the triggered event\n     */\n    async _requestCmDelete(target, event) {\n        const cmIds = this._getTargetIds(target);\n        if (cmIds.length == 0) {\n            return;\n        }\n\n        event.preventDefault();\n\n        let bodyText = null;\n        let titleText = null;\n        let delegatedsection = null;\n        if (cmIds.length == 1) {\n            const cmInfo = this.reactive.get('cm', cmIds[0]);\n            if (cmInfo.hasdelegatedsection) {\n                delegatedsection = cmInfo.delegatesectionid;\n                titleText = this.reactive.getFormatString('cmdelete_subsectiontitle');\n                bodyText = getString(\n                    'sectiondelete_info',\n                    'core_courseformat',\n                    {\n                        type: cmInfo.modname,\n                        name: cmInfo.name,\n                    }\n                );\n            } else {\n                titleText = this.reactive.getFormatString('cmdelete_title');\n                bodyText = getString(\n                    'cmdelete_info',\n                    'core_courseformat',\n                    {\n                        type: cmInfo.modname,\n                        name: cmInfo.name,\n                    }\n                );\n            }\n        } else {\n            titleText = getString('cmsdelete_title', 'core_courseformat');\n            bodyText = getString(\n                'cmsdelete_info',\n                'core_courseformat',\n                {count: cmIds.length}\n            );\n        }\n\n        const modal = await this._modalBodyRenderedPromise(ModalDeleteCancel, {\n            title: titleText,\n            body: bodyText,\n        });\n\n        modal.getRoot().on(\n            ModalEvents.delete,\n            e => {\n                // Stop the default save button behaviour which is to close the modal.\n                e.preventDefault();\n                modal.destroy();\n                this.reactive.dispatch('cmDelete', cmIds);\n                if (cmIds.length == 1 && delegatedsection && target.baseURI.includes('section.php')) {\n                    // Redirect to the course main page if the subsection is the current page.\n                    let parameters = new URLSearchParams(window.location.search);\n                    if (parameters.has('id') && parameters.get('id') == delegatedsection) {\n                        this._dispatchSectionDelete([delegatedsection], target);\n                    }\n                }\n            }\n        );\n    }\n\n    /**\n     * Handle a cm availability change request.\n     *\n     * @param {Element} target the dispatch action element\n     */\n    async _requestCmAvailability(target) {\n        const cmIds = this._getTargetIds(target);\n        if (cmIds.length == 0) {\n            return;\n        }\n        // Show the availability modal to decide which action to trigger.\n        const exporter = this.reactive.getExporter();\n        const data = {\n            allowstealth: exporter.canUseStealth(this.reactive.state, cmIds),\n        };\n        const modal = await this._modalBodyRenderedPromise(ModalSaveCancel, {\n            title: getString('availability', 'core'),\n            body: Templates.render('core_courseformat/local/content/cm/availabilitymodal', data),\n            saveButtonText: getString('apply', 'core'),\n        });\n\n        this._setupMutationRadioButtonModal(modal, cmIds);\n    }\n\n    /**\n     * Handle a section availability change request.\n     *\n     * @param {Element} target the dispatch action element\n     */\n    async _requestSectionAvailability(target) {\n        const sectionIds = this._getTargetIds(target);\n        if (sectionIds.length == 0) {\n            return;\n        }\n        const title = (sectionIds.length == 1) ? 'sectionavailability_title' : 'sectionsavailability_title';\n        // Show the availability modal to decide which action to trigger.\n        const modal = await this._modalBodyRenderedPromise(ModalSaveCancel, {\n            title: this.reactive.getFormatString(title),\n            body: Templates.render('core_courseformat/local/content/section/availabilitymodal', []),\n            saveButtonText: getString('apply', 'core'),\n        });\n\n        this._setupMutationRadioButtonModal(modal, sectionIds);\n    }\n\n    /**\n     * Add events to a mutation selector radio buttons modal.\n     * @param {Modal} modal\n     * @param {Number[]} ids the section or cm ids to apply the mutation\n     */\n    _setupMutationRadioButtonModal(modal, ids) {\n        // The save button is not enabled until the user selects an option.\n        modal.setButtonDisabled('save', true);\n\n        const submitFunction = (radio) => {\n            const mutation = radio?.value;\n            if (!mutation) {\n                return false;\n            }\n            this.reactive.dispatch(mutation, ids);\n            return true;\n        };\n\n        const modalBody = getFirst(modal.getBody());\n        const radioOptions = modalBody.querySelectorAll(this.selectors.OPTIONSRADIO);\n        radioOptions.forEach(radio => {\n            radio.addEventListener('change', () => {\n                modal.setButtonDisabled('save', false);\n            });\n            radio.parentNode.addEventListener('click', () => {\n                radio.checked = true;\n                modal.setButtonDisabled('save', false);\n            });\n            radio.parentNode.addEventListener('dblclick', dbClickEvent => {\n                if (submitFunction(radio)) {\n                    dbClickEvent.preventDefault();\n                    modal.destroy();\n                }\n            });\n        });\n\n        modal.getRoot().on(\n            ModalEvents.save,\n            () => {\n                const radio = modalBody.querySelector(`${this.selectors.OPTIONSRADIO}:checked`);\n                submitFunction(radio);\n            }\n        );\n    }\n\n    /**\n     * Disable all add sections actions.\n     *\n     * @param {boolean} locked the new locked value.\n     */\n    _setAddSectionLocked(locked) {\n        const targets = this.getElements(this.selectors.ADDSECTIONREGION);\n        targets.forEach(element => {\n            element.classList.toggle(this.classes.DISABLED, locked);\n            const addSectionElement = element.querySelector(this.selectors.ADDSECTION);\n            addSectionElement.classList.toggle(this.classes.DISABLED, locked);\n            this.setElementLocked(addSectionElement, locked);\n            // We tweak the element to show a tooltip as a title attribute.\n            if (locked) {\n                getString('sectionaddmax', 'core_courseformat')\n                    .then((text) => addSectionElement.setAttribute('title', text))\n                    .catch(Notification.exception);\n                addSectionElement.style.pointerEvents = null; // Unlocks the pointer events.\n                addSectionElement.style.userSelect = null; // Unlocks the pointer events.\n            } else {\n                addSectionElement.setAttribute('title', addSectionElement.dataset.addSections);\n            }\n        });\n        const courseAddSection = this.getElement(this.selectors.COURSEADDSECTION);\n        if (courseAddSection) {\n            const addSection = courseAddSection.querySelector(this.selectors.ADDSECTION);\n            addSection.classList.toggle(this.classes.DISPLAYNONE, locked);\n            const noMoreSections = courseAddSection.querySelector(this.selectors.MAXSECTIONSWARNING);\n            noMoreSections.classList.toggle(this.classes.DISPLAYNONE, !locked);\n        }\n    }\n\n    /**\n     * Replace an element with a copy with a different tag name.\n     *\n     * @param {Element} element the original element\n     */\n    _disableLink(element) {\n        if (element) {\n            element.style.pointerEvents = 'none';\n            element.style.userSelect = 'none';\n            element.classList.add(this.classes.DISABLED);\n            element.classList.add(this.classes.ITALIC);\n            element.setAttribute('aria-disabled', true);\n            element.addEventListener('click', event => event.preventDefault());\n        }\n    }\n\n    /**\n     * Render a modal and return a body ready promise.\n     *\n     * @param {Modal} ModalClass the modal class\n     * @param {object} modalParams the modal params\n     * @return {Promise} the modal body ready promise\n     */\n    _modalBodyRenderedPromise(ModalClass, modalParams) {\n        return new Promise((resolve, reject) => {\n            ModalClass.create(modalParams).then((modal) => {\n                modal.setRemoveOnClose(true);\n                // Handle body loading event.\n                modal.getRoot().on(ModalEvents.bodyRendered, () => {\n                    resolve(modal);\n                });\n                // Configure some extra modal params.\n                if (modalParams.saveButtonText !== undefined) {\n                    modal.setSaveButtonText(modalParams.saveButtonText);\n                }\n                if (modalParams.deleteButtonText !== undefined) {\n                    modal.setDeleteButtonText(modalParams.saveButtonText);\n                }\n                modal.show();\n                return;\n            }).catch(() => {\n                reject(`Cannot load modal content`);\n            });\n        });\n    }\n\n    /**\n     * Hide and later destroy a modal.\n     *\n     * Behat will fail if we remove the modal while some boostrap collapse is executing.\n     *\n     * @param {Modal} modal\n     * @param {HTMLElement} element the dom element to focus on.\n     */\n    _destroyModal(modal, element) {\n        modal.hide();\n        const pendingDestroy = new Pending(`courseformat/actions:destroyModal`);\n        if (element) {\n            element.focus();\n        }\n        setTimeout(() =>{\n            modal.destroy();\n            pendingDestroy.resolve();\n        }, 500);\n    }\n\n    /**\n     * Get the closest actions menu toggler to an action element.\n     *\n     * @param {HTMLElement} element the action link element\n     * @returns {HTMLElement|undefined}\n     */\n    _getClosestActionMenuToogler(element) {\n        const actionMenu = element.closest(this.selectors.ACTIONMENU);\n        if (!actionMenu) {\n            return undefined;\n        }\n        return actionMenu.querySelector(this.selectors.ACTIONMENUTOGGLER);\n    }\n}\n"],"names":["directMutations","sectionHide","sectionShow","cmHide","cmShow","cmStealth","cmMoveRight","cmMoveLeft","cmNoGroups","cmSeparateGroups","cmVisibleGroups","BaseComponent","create","name","selectors","ACTIONLINK","SECTIONLINK","CMLINK","SECTIONNODE","MODALTOGGLER","ADDSECTION","CONTENTTREE","ACTIONMENU","ACTIONMENUTOGGLER","OPTIONSRADIO","COURSEADDSECTION","MAXSECTIONSWARNING","ADDSECTIONREGION","classes","DISABLED","ITALIC","DISPLAYNONE","actions","action","mutationReference","Object","entries","Error","stateReady","state","addEventListener","this","element","_dispatchClick","_checkSectionlist","CourseEvents","sectionRefreshed","getWatchers","watch","handler","event","target","closest","classList","contains","preventDefault","actionName","dataset","methodName","_actionMethodName","undefined","_requestMutationAction","requestName","charAt","toUpperCase","slice","_setAddSectionLocked","course","sectionlist","length","maxsections","_getTargetIds","ids","_target$dataset","id","push","bulkType","_target$dataset2","bulk","reactive","get","enabled","selectedType","selection","sectionIds","pendingModalReady","Pending","editTools","_getClosestActionMenuToogler","data","getExporter","titleText","sectionInfo","sectionid","sectiontitle","title","information","getFormatString","modal","_modalBodyRenderedPromise","Modal","body","Templates","render","modalBody","getBody","forEach","sectionId","currentElement","querySelector","_disableLink","ContentTree","SECTION","TOGGLER","COLLAPSE","matches","for","getAttribute","dispatch","_destroyModal","resolve","cmIds","exporter","cmInfo","cmid","cmname","hasdelegatedsection","cmId","ENTER","selector","_expandCmMoveModalParentSections","targetSectionId","targetCmId","droppedCmIds","dropData","cmDraggableData","nextcmid","section","cmlist","component","filter","sectionnode","toggler","find","collapsibleId","attr","replace","expandNode","collapse","parentElement","modname","sectionnum","beforemod","some","hassummary","rawtitle","_dispatchSectionDelete","bodyText","count","ModalDeleteCancel","getRoot","on","ModalEvents","delete","e","destroy","baseURI","includes","window","location","href","baseurl","mutationName","delegatedsection","delegatesectionid","type","parameters","URLSearchParams","search","has","allowstealth","canUseStealth","ModalSaveCancel","saveButtonText","_setupMutationRadioButtonModal","setButtonDisabled","submitFunction","radio","mutation","value","querySelectorAll","parentNode","checked","dbClickEvent","save","locked","getElements","toggle","addSectionElement","setElementLocked","then","text","setAttribute","catch","Notification","exception","style","pointerEvents","userSelect","addSections","courseAddSection","getElement","add","ModalClass","modalParams","Promise","reject","setRemoveOnClose","bodyRendered","setSaveButtonText","deleteButtonText","setDeleteButtonText","show","hide","pendingDestroy","focus","setTimeout","actionMenu"],"mappings":"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"}