Proyectos de Subversion Moodle

Rev

Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |

{"version":3,"file":"actions.min.js","sources":["../src/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 * Various actions on modules and sections in the editing mode - hiding, duplicating, deleting, etc.\n *\n * @module     core_course/actions\n * @copyright  2016 Marina Glancy\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.3\n */\ndefine(\n    [\n        'jquery',\n        'core/ajax',\n        'core/templates',\n        'core/notification',\n        'core/str',\n        'core/url',\n        'core/yui',\n        'core/modal_copy_to_clipboard',\n        'core/modal_save_cancel',\n        'core/modal_events',\n        'core/key_codes',\n        'core/log',\n        'core_courseformat/courseeditor',\n        'core/event_dispatcher',\n        'core_course/events'\n    ],\n    function(\n        $,\n        ajax,\n        templates,\n        notification,\n        str,\n        url,\n        Y,\n        ModalCopyToClipboard,\n        ModalSaveCancel,\n        ModalEvents,\n        KeyCodes,\n        log,\n        editor,\n        EventDispatcher,\n        CourseEvents\n    ) {\n\n        // Eventually, core_courseformat/local/content/actions will handle all actions for\n        // component compatible formats and the default actions.js won't be necessary anymore.\n        // Meanwhile, we filter the migrated actions.\n        const componentActions = [\n            'moveSection', 'moveCm', 'addSection', 'deleteSection', 'cmDelete', 'cmDuplicate', 'sectionHide', 'sectionShow',\n            'cmHide', 'cmShow', 'cmStealth', 'sectionHighlight', 'sectionUnhighlight', 'cmMoveRight', 'cmMoveLeft',\n            'cmNoGroups', 'cmVisibleGroups', 'cmSeparateGroups',\n        ];\n\n        // The course reactive instance.\n        const courseeditor = editor.getCurrentCourseEditor();\n\n        // The current course format name (loaded on init).\n        let formatname;\n\n        var CSS = {\n            EDITINPROGRESS: 'editinprogress',\n            SECTIONDRAGGABLE: 'sectiondraggable',\n            EDITINGMOVE: 'editing_move'\n        };\n        var SELECTOR = {\n            ACTIVITYLI: 'li.activity',\n            ACTIONAREA: '.actions',\n            ACTIVITYACTION: 'a.cm-edit-action',\n            MENU: '.moodle-actionmenu[data-enhance=moodle-core-actionmenu]',\n            TOGGLE: '.toggle-display,.dropdown-toggle',\n            SECTIONLI: 'li.section',\n            SECTIONACTIONMENU: '.section_action_menu',\n            SECTIONITEM: '[data-for=\"section_title\"]',\n            ADDSECTIONS: '.changenumsections [data-add-sections]',\n            SECTIONBADGES: '[data-region=\"sectionbadges\"]',\n        };\n\n        Y.use('moodle-course-coursebase', function() {\n            var courseformatselector = M.course.format.get_section_selector();\n            if (courseformatselector) {\n                SELECTOR.SECTIONLI = courseformatselector;\n            }\n        });\n\n        /**\n         * Dispatch event wrapper.\n         *\n         * Old jQuery events will be replaced by native events gradually.\n         *\n         * @method dispatchEvent\n         * @param {String} eventName The name of the event\n         * @param {Object} detail Any additional details to pass into the eveent\n         * @param {Node|HTMLElement} container The point at which to dispatch the event\n         * @param {Object} options\n         * @param {Boolean} options.bubbles Whether to bubble up the DOM\n         * @param {Boolean} options.cancelable Whether preventDefault() can be called\n         * @param {Boolean} options.composed Whether the event can bubble across the ShadowDOM boundary\n         * @returns {CustomEvent}\n         */\n        const dispatchEvent = function(eventName, detail, container, options) {\n            // Most actions still uses jQuery node instead of regular HTMLElement.\n            if (!(container instanceof Element) && container.get !== undefined) {\n                container = container.get(0);\n            }\n            return EventDispatcher.dispatchEvent(eventName, detail, container, options);\n        };\n\n        /**\n         * Wrapper for Y.Moodle.core_course.util.cm.getId\n         *\n         * @param {JQuery} element\n         * @returns {Integer}\n         */\n        var getModuleId = function(element) {\n            // Check if we have a data-id first.\n            const item = element.get(0);\n            if (item.dataset.id) {\n                return item.dataset.id;\n            }\n            // Use YUI way if data-id is not present.\n            let id;\n            Y.use('moodle-course-util', function(Y) {\n                id = Y.Moodle.core_course.util.cm.getId(Y.Node(item));\n            });\n            return id;\n        };\n\n        /**\n         * Wrapper for Y.Moodle.core_course.util.cm.getName\n         *\n         * @param {JQuery} element\n         * @returns {String}\n         */\n        var getModuleName = function(element) {\n            var name;\n            Y.use('moodle-course-util', function(Y) {\n                name = Y.Moodle.core_course.util.cm.getName(Y.Node(element.get(0)));\n            });\n            // Check if we have the name in the course state.\n            const state = courseeditor.state;\n            const cmid = getModuleId(element);\n            if (!name && state && cmid) {\n                name = state.cm.get(cmid)?.name;\n            }\n            return name;\n        };\n\n        /**\n         * Wrapper for M.util.add_spinner for an activity\n         *\n         * @param {JQuery} activity\n         * @returns {Node}\n         */\n        var addActivitySpinner = function(activity) {\n            activity.addClass(CSS.EDITINPROGRESS);\n            var actionarea = activity.find(SELECTOR.ACTIONAREA).get(0);\n            if (actionarea) {\n                var spinner = M.util.add_spinner(Y, Y.Node(actionarea));\n                spinner.show();\n                // Lock the activity state element.\n                if (activity.data('id') !== undefined) {\n                    courseeditor.dispatch('cmLock', [activity.data('id')], true);\n                }\n                return spinner;\n            }\n            return null;\n        };\n\n        /**\n         * Wrapper for M.util.add_spinner for a section\n         *\n         * @param {JQuery} sectionelement\n         * @returns {Node}\n         */\n        var addSectionSpinner = function(sectionelement) {\n            sectionelement.addClass(CSS.EDITINPROGRESS);\n            var actionarea = sectionelement.find(SELECTOR.SECTIONACTIONMENU).get(0);\n            if (actionarea) {\n                var spinner = M.util.add_spinner(Y, Y.Node(actionarea));\n                spinner.show();\n                // Lock the section state element.\n                if (sectionelement.data('id') !== undefined) {\n                    courseeditor.dispatch('sectionLock', [sectionelement.data('id')], true);\n                }\n                return spinner;\n            }\n            return null;\n        };\n\n        /**\n         * Wrapper for M.util.add_lightbox\n         *\n         * @param {JQuery} sectionelement\n         * @returns {Node}\n         */\n        var addSectionLightbox = function(sectionelement) {\n            const item = sectionelement.get(0);\n            var lightbox = M.util.add_lightbox(Y, Y.Node(item));\n            if (item.dataset.for == 'section' && item.dataset.id) {\n                courseeditor.dispatch('sectionLock', [item.dataset.id], true);\n                lightbox.setAttribute('data-state', 'section');\n                lightbox.setAttribute('data-state-id', item.dataset.id);\n            }\n            lightbox.show();\n            return lightbox;\n        };\n\n        /**\n         * Removes the spinner element\n         *\n         * @param {JQuery} element\n         * @param {Node} spinner\n         * @param {Number} delay\n         */\n        var removeSpinner = function(element, spinner, delay) {\n            window.setTimeout(function() {\n                element.removeClass(CSS.EDITINPROGRESS);\n                if (spinner) {\n                    spinner.hide();\n                }\n                // Unlock the state element.\n                if (element.data('id') !== undefined) {\n                    const mutation = (element.data('for') === 'section') ? 'sectionLock' : 'cmLock';\n                    courseeditor.dispatch(mutation, [element.data('id')], false);\n                }\n            }, delay);\n        };\n\n        /**\n         * Removes the lightbox element\n         *\n         * @param {Node} lightbox lighbox YUI element returned by addSectionLightbox\n         * @param {Number} delay\n         */\n        var removeLightbox = function(lightbox, delay) {\n            if (lightbox) {\n                window.setTimeout(function() {\n                    lightbox.hide();\n                    // Unlock state if necessary.\n                    if (lightbox.getAttribute('data-state')) {\n                        courseeditor.dispatch(\n                            `${lightbox.getAttribute('data-state')}Lock`,\n                            [lightbox.getAttribute('data-state-id')],\n                            false\n                        );\n                    }\n                }, delay);\n            }\n        };\n\n        /**\n         * Initialise action menu for the element (section or module)\n         *\n         * @param {String} elementid CSS id attribute of the element\n         */\n        var initActionMenu = function(elementid) {\n            // Initialise action menu in the new activity.\n            Y.use('moodle-course-coursebase', function() {\n                M.course.coursebase.invoke_function('setup_for_resource', '#' + elementid);\n            });\n            if (M.core.actionmenu && M.core.actionmenu.newDOMNode) {\n                M.core.actionmenu.newDOMNode(Y.one('#' + elementid));\n            }\n        };\n\n        /**\n         * Returns focus to the element that was clicked or \"Edit\" link if element is no longer visible.\n         *\n         * @param {String} elementId CSS id attribute of the element\n         * @param {String} action data-action property of the element that was clicked\n         */\n        var focusActionItem = function(elementId, action) {\n            var mainelement = $('#' + elementId);\n            var selector = '[data-action=' + action + ']';\n            if (action === 'groupsseparate' || action === 'groupsvisible' || action === 'groupsnone') {\n                // New element will have different data-action.\n                selector = '[data-action=groupsseparate],[data-action=groupsvisible],[data-action=groupsnone]';\n            }\n            if (mainelement.find(selector).is(':visible')) {\n                mainelement.find(selector).focus();\n            } else {\n                // Element not visible, focus the \"Edit\" link.\n                mainelement.find(SELECTOR.MENU).find(SELECTOR.TOGGLE).focus();\n            }\n        };\n\n        /**\n         * Find next <a> after the element\n         *\n         * @param {JQuery} mainElement element that is about to be deleted\n         * @returns {JQuery}\n         */\n        var findNextFocusable = function(mainElement) {\n            var tabables = $(\"a:visible\");\n            var isInside = false;\n            var foundElement = null;\n            tabables.each(function() {\n                if ($.contains(mainElement[0], this)) {\n                    isInside = true;\n                } else if (isInside) {\n                    foundElement = this;\n                    return false; // Returning false in .each() is equivalent to \"break;\" inside the loop in php.\n                }\n                return true;\n            });\n            return foundElement;\n        };\n\n        /**\n         * Performs an action on a module (moving, deleting, duplicating, hiding, etc.)\n         *\n         * @param {JQuery} moduleElement activity element we perform action on\n         * @param {Number} cmid\n         * @param {JQuery} target the element (menu item) that was clicked\n         */\n        var editModule = function(moduleElement, cmid, target) {\n            var action = target.attr('data-action');\n            var spinner = addActivitySpinner(moduleElement);\n            var promises = ajax.call([{\n                methodname: 'core_course_edit_module',\n                args: {id: cmid,\n                    action: action,\n                    sectionreturn: target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : null\n                }\n            }], true);\n\n            var lightbox;\n            if (action === 'duplicate') {\n                lightbox = addSectionLightbox(target.closest(SELECTOR.SECTIONLI));\n            }\n            $.when.apply($, promises)\n                .done(function(data) {\n                    var elementToFocus = findNextFocusable(moduleElement);\n                    moduleElement.replaceWith(data);\n                    let affectedids = [];\n                    // Initialise action menu for activity(ies) added as a result of this.\n                    $('<div>' + data + '</div>').find(SELECTOR.ACTIVITYLI).each(function(index) {\n                        initActionMenu($(this).attr('id'));\n                        if (index === 0) {\n                            focusActionItem($(this).attr('id'), action);\n                            elementToFocus = null;\n                        }\n                        // Save any activity id in cmids.\n                        affectedids.push(getModuleId($(this)));\n                    });\n                    // In case of activity deletion focus the next focusable element.\n                    if (elementToFocus) {\n                        elementToFocus.focus();\n                    }\n                    // Remove spinner and lightbox with a delay.\n                    removeSpinner(moduleElement, spinner, 400);\n                    removeLightbox(lightbox, 400);\n                    // Trigger event that can be observed by course formats.\n                    moduleElement.trigger($.Event('coursemoduleedited', {ajaxreturn: data, action: action}));\n\n                    // Modify cm state.\n                    courseeditor.dispatch('legacyActivityAction', action, cmid, affectedids);\n\n                }).fail(function(ex) {\n                    // Remove spinner and lightbox.\n                    removeSpinner(moduleElement, spinner);\n                    removeLightbox(lightbox);\n                    // Trigger event that can be observed by course formats.\n                    var e = $.Event('coursemoduleeditfailed', {exception: ex, action: action});\n                    moduleElement.trigger(e);\n                    if (!e.isDefaultPrevented()) {\n                        notification.exception(ex);\n                    }\n                });\n        };\n\n        /**\n         * Requests html for the module via WS core_course_get_module and updates the module on the course page\n         *\n         * Used after d&d of the module to another section\n         *\n         * @param {JQuery|Element} element\n         * @param {Number} cmid\n         * @param {Number} sectionreturn\n         * @return {Promise} the refresh promise\n         */\n        var refreshModule = function(element, cmid, sectionreturn) {\n\n            if (sectionreturn === undefined) {\n                sectionreturn = courseeditor.sectionReturn;\n            }\n\n            const activityElement = $(element);\n            var spinner = addActivitySpinner(activityElement);\n            var promises = ajax.call([{\n                methodname: 'core_course_get_module',\n                args: {id: cmid, sectionreturn: sectionreturn}\n            }], true);\n\n            return new Promise((resolve, reject) => {\n                $.when.apply($, promises)\n                    .done(function(data) {\n                        removeSpinner(activityElement, spinner, 400);\n                        replaceActivityHtmlWith(data);\n                        resolve(data);\n                    }).fail(function() {\n                        removeSpinner(activityElement, spinner);\n                        reject();\n                    });\n            });\n        };\n\n        /**\n         * Requests html for the section via WS core_course_edit_section and updates the section on the course page\n         *\n         * @param {JQuery|Element} element\n         * @param {Number} sectionid\n         * @param {Number} sectionreturn\n         * @return {Promise} the refresh promise\n         */\n        var refreshSection = function(element, sectionid, sectionreturn) {\n\n            if (sectionreturn === undefined) {\n                sectionreturn = courseeditor.sectionReturn;\n            }\n\n            const sectionElement = $(element);\n            const action = 'refresh';\n            const promises = ajax.call([{\n                methodname: 'core_course_edit_section',\n                args: {id: sectionid, action, sectionreturn},\n            }], true);\n\n            var spinner = addSectionSpinner(sectionElement);\n            return new Promise((resolve, reject) => {\n                $.when.apply($, promises)\n                    .done(dataencoded => {\n\n                        removeSpinner(sectionElement, spinner);\n                        const data = $.parseJSON(dataencoded);\n\n                        const newSectionElement = $(data.content);\n                        sectionElement.replaceWith(newSectionElement);\n\n                        // Init modules menus.\n                        $(`${SELECTOR.SECTIONLI}#${sectionid} ${SELECTOR.ACTIVITYLI}`).each(\n                            (index, activity) => {\n                                initActionMenu(activity.data('id'));\n                            }\n                        );\n\n                        // Trigger event that can be observed by course formats.\n                        const event = dispatchEvent(\n                            CourseEvents.sectionRefreshed,\n                            {\n                                ajaxreturn: data,\n                                action: action,\n                                newSectionElement: newSectionElement.get(0),\n                            },\n                            newSectionElement\n                        );\n\n                        if (!event.defaultPrevented) {\n                            defaultEditSectionHandler(\n                                newSectionElement, $(SELECTOR.SECTIONLI + '#' + sectionid),\n                                data,\n                                formatname,\n                                sectionid\n                            );\n                        }\n                        resolve(data);\n                    }).fail(ex => {\n                        // Trigger event that can be observed by course formats.\n                        const event = dispatchEvent(\n                            'coursesectionrefreshfailed',\n                            {exception: ex, action: action},\n                            sectionElement\n                        );\n                        if (!event.defaultPrevented) {\n                            notification.exception(ex);\n                        }\n                        reject();\n                    });\n            });\n        };\n\n        /**\n         * Displays the delete confirmation to delete a module\n         *\n         * @param {JQuery} mainelement activity element we perform action on\n         * @param {function} onconfirm function to execute on confirm\n         */\n        var confirmDeleteModule = function(mainelement, onconfirm) {\n            var modtypename = mainelement.attr('class').match(/modtype_([^\\s]*)/)[1];\n            var modulename = getModuleName(mainelement);\n\n            str.get_string('pluginname', modtypename).done(function(pluginname) {\n                var plugindata = {\n                    type: pluginname,\n                    name: modulename\n                };\n                str.get_strings([\n                    {key: 'confirm', component: 'core'},\n                    {key: modulename === null ? 'deletechecktype' : 'deletechecktypename', param: plugindata},\n                    {key: 'yes'},\n                    {key: 'no'}\n                ]).done(function(s) {\n                        notification.confirm(s[0], s[1], s[2], s[3], onconfirm);\n                    }\n                );\n            });\n        };\n\n        /**\n         * Displays the delete confirmation to delete a section\n         *\n         * @param {String} message confirmation message\n         * @param {function} onconfirm function to execute on confirm\n         */\n        var confirmEditSection = function(message, onconfirm) {\n            str.get_strings([\n                {key: 'confirm'}, // TODO link text\n                {key: 'yes'},\n                {key: 'no'}\n            ]).done(function(s) {\n                    notification.confirm(s[0], message, s[1], s[2], onconfirm);\n                }\n            );\n        };\n\n        /**\n         * Replaces an action menu item with another one (for example Show->Hide, Set marker->Remove marker)\n         *\n         * @param {JQuery} actionitem\n         * @param {String} image new image name (\"i/show\", \"i/hide\", etc.)\n         * @param {String} stringname new string for the action menu item\n         * @param {String} stringcomponent\n         * @param {String} newaction new value for data-action attribute of the link\n         * @return {Promise} promise which is resolved when the replacement has completed\n         */\n        var replaceActionItem = function(actionitem, image, stringname,\n                                           stringcomponent, newaction) {\n\n            var stringRequests = [{key: stringname, component: stringcomponent}];\n            // Do not provide an icon with duplicate, different text to the menu item.\n\n            return str.get_strings(stringRequests).then(function(strings) {\n                actionitem.find('span.menu-action-text').html(strings[0]);\n\n                return templates.renderPix(image, 'core');\n            }).then(function(pixhtml) {\n                actionitem.find('.icon').replaceWith(pixhtml);\n                actionitem.attr('data-action', newaction);\n                return;\n            }).catch(notification.exception);\n        };\n\n        /**\n         * Default post-processing for section AJAX edit actions.\n         *\n         * This can be overridden in course formats by listening to event coursesectionedited:\n         *\n         * $('body').on('coursesectionedited', 'li.section', function(e) {\n         *     var action = e.action,\n         *         sectionElement = $(e.target),\n         *         data = e.ajaxreturn;\n         *     // ... Do some processing here.\n         *     e.preventDefault(); // Prevent default handler.\n         * });\n         *\n         * @param {JQuery} sectionElement\n         * @param {JQuery} actionItem\n         * @param {Object} data\n         * @param {String} courseformat\n         * @param {Number} sectionid\n         */\n        var defaultEditSectionHandler = function(sectionElement, actionItem, data, courseformat, sectionid) {\n            var action = actionItem.attr('data-action');\n            if (action === 'hide' || action === 'show') {\n                if (action === 'hide') {\n                    sectionElement.addClass('hidden');\n                    setSectionBadge(sectionElement[0], 'hiddenfromstudents', true, false);\n                    replaceActionItem(actionItem, 'i/show',\n                        'showfromothers', 'format_' + courseformat, 'show');\n                } else {\n                    setSectionBadge(sectionElement[0], 'hiddenfromstudents', false, false);\n                    sectionElement.removeClass('hidden');\n                    replaceActionItem(actionItem, 'i/hide',\n                        'hidefromothers', 'format_' + courseformat, 'hide');\n                }\n                // Replace the modules with new html (that indicates that they are now hidden or not hidden).\n                if (data.modules !== undefined) {\n                    for (var i in data.modules) {\n                        replaceActivityHtmlWith(data.modules[i]);\n                    }\n                }\n                // Replace the section availability information.\n                if (data.section_availability !== undefined) {\n                    sectionElement.find('.section_availability').first().replaceWith(data.section_availability);\n                }\n                // Modify course state.\n                const section = courseeditor.state.section.get(sectionid);\n                if (section !== undefined) {\n                    courseeditor.dispatch('sectionState', [sectionid]);\n                }\n            } else if (action === 'setmarker') {\n                var oldmarker = $(SELECTOR.SECTIONLI + '.current'),\n                    oldActionItem = oldmarker.find(SELECTOR.SECTIONACTIONMENU + ' ' + 'a[data-action=removemarker]');\n                oldmarker.removeClass('current');\n                replaceActionItem(oldActionItem, 'i/marker',\n                    'highlight', 'core', 'setmarker');\n                sectionElement.addClass('current');\n                replaceActionItem(actionItem, 'i/marked',\n                    'highlightoff', 'core', 'removemarker');\n                courseeditor.dispatch('legacySectionAction', action, sectionid);\n                setSectionBadge(sectionElement[0], 'iscurrent', true, true);\n            } else if (action === 'removemarker') {\n                sectionElement.removeClass('current');\n                replaceActionItem(actionItem, 'i/marker',\n                    'highlight', 'core', 'setmarker');\n                courseeditor.dispatch('legacySectionAction', action, sectionid);\n                setSectionBadge(sectionElement[0], 'iscurrent', false, true);\n            }\n        };\n\n        /**\n         * Get the focused element path in an activity if any.\n         *\n         * This method is used to restore focus when the activity HTML is refreshed.\n         * Only the main course editor elements can be refocused as they are always present\n         * even if the activity content changes.\n         *\n         * @param {String} id the element id the activity element\n         * @return {String|undefined} the inner path of the focused element or undefined\n         */\n        const getActivityFocusedElement = function(id) {\n            const element = document.getElementById(id);\n            if (!element || !element.contains(document.activeElement)) {\n                return undefined;\n            }\n            // Check if the actions menu toggler is focused.\n            if (element.querySelector(SELECTOR.ACTIONAREA).contains(document.activeElement)) {\n                return `${SELECTOR.ACTIONAREA} [tabindex=\"0\"]`;\n            }\n            // Return the current element id if any.\n            if (document.activeElement.id) {\n                return `#${document.activeElement.id}`;\n            }\n            return undefined;\n        };\n\n        /**\n         * Replaces the course module with the new html (used to update module after it was edited or its visibility was changed).\n         *\n         * @param {String} activityHTML\n         */\n        var replaceActivityHtmlWith = function(activityHTML) {\n            $('<div>' + activityHTML + '</div>').find(SELECTOR.ACTIVITYLI).each(function() {\n                // Extract id from the new activity html.\n                var id = $(this).attr('id');\n                // Check if the current focused element is inside the activity.\n                let focusedPath = getActivityFocusedElement(id);\n                // Find the existing element with the same id and replace its contents with new html.\n                $(SELECTOR.ACTIVITYLI + '#' + id).replaceWith(activityHTML);\n                // Initialise action menu.\n                initActionMenu(id);\n                // Re-focus the previous elements.\n                if (focusedPath) {\n                    const newItem = document.getElementById(id);\n                    newItem.querySelector(focusedPath)?.focus();\n                }\n\n            });\n        };\n\n        /**\n         * Performs an action on a module (moving, deleting, duplicating, hiding, etc.)\n         *\n         * @param {JQuery} sectionElement section element we perform action on\n         * @param {Nunmber} sectionid\n         * @param {JQuery} target the element (menu item) that was clicked\n         * @param {String} courseformat\n         * @return {boolean} true the action call is sent to the server or false if it is ignored.\n         */\n        var editSection = function(sectionElement, sectionid, target, courseformat) {\n            var action = target.attr('data-action'),\n                sectionreturn = target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : null;\n\n            // Filter direct component handled actions.\n            if (courseeditor.supportComponents && componentActions.includes(action)) {\n                return false;\n            }\n\n            var spinner = addSectionSpinner(sectionElement);\n            var promises = ajax.call([{\n                methodname: 'core_course_edit_section',\n                args: {id: sectionid, action: action, sectionreturn: sectionreturn}\n            }], true);\n\n            var lightbox = addSectionLightbox(sectionElement);\n            $.when.apply($, promises)\n                .done(function(dataencoded) {\n                    var data = $.parseJSON(dataencoded);\n                    removeSpinner(sectionElement, spinner);\n                    removeLightbox(lightbox);\n                    sectionElement.find(SELECTOR.SECTIONACTIONMENU).find(SELECTOR.TOGGLE).focus();\n                    // Trigger event that can be observed by course formats.\n                    var e = $.Event('coursesectionedited', {ajaxreturn: data, action: action});\n                    sectionElement.trigger(e);\n                    if (!e.isDefaultPrevented()) {\n                        defaultEditSectionHandler(sectionElement, target, data, courseformat, sectionid);\n                    }\n                }).fail(function(ex) {\n                    // Remove spinner and lightbox.\n                    removeSpinner(sectionElement, spinner);\n                    removeLightbox(lightbox);\n                    // Trigger event that can be observed by course formats.\n                    var e = $.Event('coursesectioneditfailed', {exception: ex, action: action});\n                    sectionElement.trigger(e);\n                    if (!e.isDefaultPrevented()) {\n                        notification.exception(ex);\n                    }\n                });\n            return true;\n        };\n\n        /**\n         * Sets the section badge in the section header.\n         *\n         * @param {JQuery} sectionElement section element we perform action on\n         * @param {String} badgetype the type of badge this is for\n         * @param {bool} add true to add, false to remove\n         * @param {boolean} removeOther in case of adding a badge, whether to remove all other.\n         */\n        var setSectionBadge = function(sectionElement, badgetype, add, removeOther) {\n            const sectionbadges = sectionElement.querySelector(SELECTOR.SECTIONBADGES);\n            if (!sectionbadges) {\n                return;\n            }\n            const badge = sectionbadges.querySelector('[data-type=\"' + badgetype + '\"]');\n            if (!badge) {\n                return;\n            }\n            if (add) {\n                if (removeOther) {\n                    document.querySelectorAll('[data-type=\"' + badgetype + '\"]').forEach((b) => {\n                        b.classList.add('d-none');\n                    });\n                }\n                badge.classList.remove('d-none');\n            } else {\n                badge.classList.add('d-none');\n            }\n        };\n\n        // Register a function to be executed after D&D of an activity.\n        Y.use('moodle-course-coursebase', function() {\n            M.course.coursebase.register_module({\n                // Ignore camelcase eslint rule for the next line because it is an expected name of the callback.\n                // eslint-disable-next-line camelcase\n                set_visibility_resource_ui: function(args) {\n                    var mainelement = $(args.element.getDOMNode());\n                    var cmid = getModuleId(mainelement);\n                    if (cmid) {\n                        var sectionreturn = mainelement.find('.' + CSS.EDITINGMOVE).attr('data-sectionreturn');\n                        refreshModule(mainelement, cmid, sectionreturn);\n                    }\n                },\n                /**\n                 * Update the course state when some cm is moved via YUI.\n                 * @param {*} params\n                 */\n                updateMovedCmState: (params) => {\n                    const state = courseeditor.state;\n\n                    // Update old section.\n                    const cm = state.cm.get(params.cmid);\n                    if (cm !== undefined) {\n                        courseeditor.dispatch('sectionState', [cm.sectionid]);\n                    }\n                    // Update cm state.\n                    courseeditor.dispatch('cmState', [params.cmid]);\n                },\n                /**\n                 * Update the course state when some section is moved via YUI.\n                 */\n                updateMovedSectionState: () => {\n                    courseeditor.dispatch('courseState');\n                },\n            });\n        });\n\n        // From Moodle 4.0 all edit actions are being re-implemented as state mutation.\n        // This means all method from this \"actions\" module will be deprecated when all the course\n        // interface is migrated to reactive components.\n        // Most legacy actions did not provide enough information to regenarate the course so they\n        // use the mutations courseState, sectionState and cmState to get the updated state from\n        // the server. However, some activity actions where we can prevent an extra webservice\n        // call by implementing an adhoc mutation.\n        courseeditor.addMutations({\n            /**\n             * Compatibility function to update Moodle 4.0 course state using legacy actions.\n             *\n             * This method only updates some actions which does not require to use cmState mutation\n             * to get updated data form the server.\n             *\n             * @param {Object} statemanager the current state in read write mode\n             * @param {String} action the performed action\n             * @param {Number} cmid the affected course module id\n             * @param {Array} affectedids all affected cm ids (for duplicate action)\n             */\n            legacyActivityAction: function(statemanager, action, cmid, affectedids) {\n\n                const state = statemanager.state;\n                const cm = state.cm.get(cmid);\n                if (cm === undefined) {\n                    return;\n                }\n                const section = state.section.get(cm.sectionid);\n                if (section === undefined) {\n                    return;\n                }\n\n                // Send the element is locked.\n                courseeditor.dispatch('cmLock', [cm.id], true);\n\n                // Now we do the real mutation.\n                statemanager.setReadOnly(false);\n\n                // This unlocked will take effect when the read only is restored.\n                cm.locked = false;\n\n                switch (action) {\n                    case 'delete':\n                        // Remove from section.\n                        section.cmlist = section.cmlist.reduce(\n                            (cmlist, current) => {\n                                if (current != cmid) {\n                                    cmlist.push(current);\n                                }\n                                return cmlist;\n                            },\n                            []\n                        );\n                        // Delete form list.\n                        state.cm.delete(cmid);\n                        break;\n\n                    case 'hide':\n                    case 'show':\n                    case 'duplicate':\n                        courseeditor.dispatch('cmState', affectedids);\n                        break;\n                }\n                statemanager.setReadOnly(true);\n            },\n            legacySectionAction: function(statemanager, action, sectionid) {\n\n                const state = statemanager.state;\n                const section = state.section.get(sectionid);\n                if (section === undefined) {\n                    return;\n                }\n\n                // Send the element is locked. Reactive events are only triggered when the state\n                // read only mode is restored. We want to notify the interface the element is\n                // locked so we need to do a quick lock operation before performing the rest\n                // of the mutation.\n                statemanager.setReadOnly(false);\n                section.locked = true;\n                statemanager.setReadOnly(true);\n\n                // Now we do the real mutation.\n                statemanager.setReadOnly(false);\n\n                // This locked will take effect when the read only is restored.\n                section.locked = false;\n\n                switch (action) {\n                    case 'setmarker':\n                        // Remove previous marker.\n                        state.section.forEach((current) => {\n                            if (current.id != sectionid) {\n                                current.current = false;\n                            }\n                        });\n                        section.current = true;\n                        break;\n\n                    case 'removemarker':\n                        section.current = false;\n                        break;\n                }\n                statemanager.setReadOnly(true);\n            },\n        });\n\n        return /** @alias module:core_course/actions */ {\n\n            /**\n             * Initialises course page\n             *\n             * @method init\n             * @param {String} courseformat name of the current course format (for fetching strings)\n             */\n            initCoursePage: function(courseformat) {\n\n                formatname = courseformat;\n\n                // Add a handler for course module actions.\n                $('body').on('click keypress', SELECTOR.ACTIVITYLI + ' ' +\n                        SELECTOR.ACTIVITYACTION + '[data-action]', function(e) {\n                    if (e.type === 'keypress' && e.keyCode !== 13) {\n                        return;\n                    }\n                    var actionItem = $(this),\n                        moduleElement = actionItem.closest(SELECTOR.ACTIVITYLI),\n                        action = actionItem.attr('data-action'),\n                        moduleId = getModuleId(moduleElement);\n                    switch (action) {\n                        case 'moveleft':\n                        case 'moveright':\n                        case 'delete':\n                        case 'duplicate':\n                        case 'hide':\n                        case 'stealth':\n                        case 'show':\n                        case 'groupsseparate':\n                        case 'groupsvisible':\n                        case 'groupsnone':\n                            break;\n                        default:\n                            // Nothing to do here!\n                            return;\n                    }\n                    if (!moduleId) {\n                        return;\n                    }\n                    e.preventDefault();\n                    if (action === 'delete') {\n                        // Deleting requires confirmation.\n                        confirmDeleteModule(moduleElement, function() {\n                            editModule(moduleElement, moduleId, actionItem);\n                        });\n                    } else {\n                        editModule(moduleElement, moduleId, actionItem);\n                    }\n                });\n\n                // Add a handler for section show/hide actions.\n                $('body').on('click keypress', SELECTOR.SECTIONLI + ' ' +\n                            SELECTOR.SECTIONACTIONMENU + '[data-sectionid] ' +\n                            'a[data-action]', function(e) {\n                    if (e.type === 'keypress' && e.keyCode !== 13) {\n                        return;\n                    }\n                    var actionItem = $(this),\n                        sectionElement = actionItem.closest(SELECTOR.SECTIONLI),\n                        sectionId = actionItem.closest(SELECTOR.SECTIONACTIONMENU).attr('data-sectionid');\n\n                    if (actionItem.attr('data-action') === 'permalink') {\n                        e.preventDefault();\n                        ModalCopyToClipboard.create({\n                            text: actionItem.attr('href'),\n                        }, str.get_string('sectionlink', 'course')\n                        );\n                        return;\n                    }\n\n                    let isExecuted = true;\n                    if (actionItem.attr('data-confirm')) {\n                        // Action requires confirmation.\n                        confirmEditSection(actionItem.attr('data-confirm'), function() {\n                            isExecuted = editSection(sectionElement, sectionId, actionItem, courseformat);\n                        });\n                    } else {\n                        isExecuted = editSection(sectionElement, sectionId, actionItem, courseformat);\n                    }\n                    // Prevent any other module from capturing the action if it is already in execution.\n                    if (isExecuted) {\n                        e.preventDefault();\n                    }\n                });\n\n                // The section and activity names are edited using inplace editable.\n                // The \"update\" jQuery event must be captured in order to update the course state.\n                $('body').on('updated', `${SELECTOR.SECTIONITEM} [data-inplaceeditable]`, function(e) {\n                    if (e.ajaxreturn && e.ajaxreturn.itemid) {\n                        const state = courseeditor.state;\n                        const section = state.section.get(e.ajaxreturn.itemid);\n                        if (section !== undefined) {\n                            courseeditor.dispatch('sectionState', [e.ajaxreturn.itemid]);\n                        }\n                    }\n                });\n                $('body').on('updated', `${SELECTOR.ACTIVITYLI} [data-inplaceeditable]`, function(e) {\n                    if (e.ajaxreturn && e.ajaxreturn.itemid) {\n                        courseeditor.dispatch('cmState', [e.ajaxreturn.itemid]);\n                    }\n                });\n\n                // Component-based formats don't use modals to create sections.\n                if (courseeditor.supportComponents && componentActions.includes('addSection')) {\n                    return;\n                }\n\n                // Add a handler for \"Add sections\" link to ask for a number of sections to add.\n                const trigger = $(SELECTOR.ADDSECTIONS);\n                const modalTitle = trigger.attr('data-add-sections');\n                const newSections = trigger.attr('data-new-sections');\n                str.get_string('numberweeks')\n                .then(function(strNumberSections) {\n                    var modalBody = $('<div><label for=\"add_section_numsections\"></label> ' +\n                        '<input id=\"add_section_numsections\" type=\"number\" min=\"1\" max=\"' + newSections + '\" value=\"1\"></div>');\n                    modalBody.find('label').html(strNumberSections);\n\n                    return modalBody.html();\n                })\n                .then((body) => ModalSaveCancel.create({\n                    body,\n                    title: modalTitle,\n                }))\n                .then(function(modal) {\n                    var numSections = $(modal.getBody()).find('#add_section_numsections'),\n                    addSections = function() {\n                        // Check if value of the \"Number of sections\" is a valid positive integer and redirect\n                        // to adding a section script.\n                        if ('' + parseInt(numSections.val()) === numSections.val() && parseInt(numSections.val()) >= 1) {\n                            document.location = trigger.attr('href') + '&numsections=' + parseInt(numSections.val());\n                        }\n                    };\n                    modal.setSaveButtonText(modalTitle);\n                    modal.getRoot().on(ModalEvents.shown, function() {\n                        // When modal is shown focus and select the input and add a listener to keypress of \"Enter\".\n                        numSections.focus().select().on('keydown', function(e) {\n                            if (e.keyCode === KeyCodes.enter) {\n                                addSections();\n                            }\n                        });\n                    });\n                    modal.getRoot().on(ModalEvents.save, function(e) {\n                        // When modal \"Add\" button is pressed.\n                        e.preventDefault();\n                        addSections();\n                    });\n\n                    trigger.on('click', (e) => {\n                        e.preventDefault();\n                        modal.show();\n                    });\n\n                    return modal;\n                })\n                .catch(notification.exception);\n            },\n\n            /**\n             * Replaces a section action menu item with another one (for example Show->Hide, Set marker->Remove marker)\n             *\n             * This method can be used by course formats in their listener to the coursesectionedited event\n             *\n             * @deprecated since Moodle 3.9\n             * @param {JQuery} sectionelement\n             * @param {String} selector CSS selector inside the section element, for example \"a[data-action=show]\"\n             * @param {String} image new image name (\"i/show\", \"i/hide\", etc.)\n             * @param {String} stringname new string for the action menu item\n             * @param {String} stringcomponent\n             * @param {String} newaction new value for data-action attribute of the link\n             */\n            replaceSectionActionItem: function(sectionelement, selector, image, stringname,\n                                                    stringcomponent, newaction) {\n                log.debug('replaceSectionActionItem() is deprecated and will be removed.');\n                var actionitem = sectionelement.find(SELECTOR.SECTIONACTIONMENU + ' ' + selector);\n                replaceActionItem(actionitem, image, stringname, stringcomponent, newaction);\n            },\n            // Method to refresh a module.\n            refreshModule,\n            refreshSection,\n        };\n    });\n"],"names":["define","$","ajax","templates","notification","str","url","Y","ModalCopyToClipboard","ModalSaveCancel","ModalEvents","KeyCodes","log","editor","EventDispatcher","CourseEvents","componentActions","courseeditor","getCurrentCourseEditor","formatname","CSS","SELECTOR","ACTIVITYLI","ACTIONAREA","ACTIVITYACTION","MENU","TOGGLE","SECTIONLI","SECTIONACTIONMENU","SECTIONITEM","ADDSECTIONS","SECTIONBADGES","use","courseformatselector","M","course","format","get_section_selector","dispatchEvent","eventName","detail","container","options","Element","undefined","get","getModuleId","element","item","dataset","id","Moodle","core_course","util","cm","getId","Node","addActivitySpinner","activity","addClass","actionarea","find","spinner","add_spinner","show","data","dispatch","addSectionSpinner","sectionelement","addSectionLightbox","lightbox","add_lightbox","for","setAttribute","removeSpinner","delay","window","setTimeout","removeClass","hide","mutation","removeLightbox","getAttribute","initActionMenu","elementid","coursebase","invoke_function","core","actionmenu","newDOMNode","one","editModule","moduleElement","cmid","target","action","attr","promises","call","methodname","args","sectionreturn","closest","when","apply","done","mainElement","tabables","isInside","foundElement","elementToFocus","each","contains","this","replaceWith","affectedids","index","elementId","mainelement","selector","is","focus","focusActionItem","push","trigger","Event","ajaxreturn","fail","ex","e","exception","isDefaultPrevented","refreshModule","sectionReturn","activityElement","Promise","resolve","reject","replaceActivityHtmlWith","confirmDeleteModule","onconfirm","modtypename","match","modulename","name","getName","state","_state$cm$get","getModuleName","get_string","pluginname","plugindata","type","get_strings","key","component","param","s","confirm","replaceActionItem","actionitem","image","stringname","stringcomponent","newaction","stringRequests","then","strings","html","renderPix","pixhtml","catch","defaultEditSectionHandler","sectionElement","actionItem","courseformat","sectionid","setSectionBadge","modules","i","section_availability","first","section","oldmarker","oldActionItem","activityHTML","focusedPath","document","getElementById","activeElement","querySelector","getActivityFocusedElement","editSection","supportComponents","includes","dataencoded","parseJSON","badgetype","add","removeOther","sectionbadges","badge","querySelectorAll","forEach","b","classList","remove","register_module","set_visibility_resource_ui","getDOMNode","updateMovedCmState","params","updateMovedSectionState","addMutations","legacyActivityAction","statemanager","setReadOnly","locked","cmlist","reduce","current","delete","legacySectionAction","initCoursePage","on","keyCode","moduleId","preventDefault","sectionId","create","text","isExecuted","message","itemid","modalTitle","newSections","strNumberSections","modalBody","body","title","modal","numSections","getBody","addSections","parseInt","val","location","setSaveButtonText","getRoot","shown","select","enter","save","replaceSectionActionItem","debug","refreshSection","newSectionElement","content","sectionRefreshed","defaultPrevented"],"mappings":"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"}