{"version":3,"file":"actions.min.js","sources":["https:\/\/www.alsg.org\/home\/course\/amd\/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 .\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_factory',\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 ModalFactory,\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', 'sectionHide', 'sectionShow',\n 'cmHide', 'cmShow', 'cmStealth', 'cmMoveRight', 'cmMoveLeft',\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 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') : 0\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 $('