mirrored from git://git.moodle.org/moodle.git
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
/
actions.min.js.map
1 lines (1 loc) · 33.1 KB
/
actions.min.js.map
1
{"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 ModalFactory from 'core/modal_factory';\nimport ModalEvents from 'core/modal_events';\nimport Templates from 'core/templates';\nimport {prefetchStrings} from 'core/prefetch';\nimport {get_string as getString} from 'core/str';\nimport {getList, getFirst} from 'core/normalise';\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';\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};\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 };\n // Component css classes.\n this.classes = {\n DISABLED: `disabled`,\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 sectionId = target.dataset.id;\n if (!sectionId) {\n return;\n }\n const sectionInfo = this.reactive.get('section', sectionId);\n\n event.preventDefault();\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\n // Add the target section id and title.\n data.sectionid = sectionInfo.id;\n data.sectiontitle = sectionInfo.title;\n\n // Build the modal parameters from the event data.\n const modalParams = {\n title: getString('movecoursesection', 'core'),\n body: Templates.render('core_courseformat/local/content/movesection', data),\n };\n\n // Create the modal.\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n const modalBody = getList(modal.getBody())[0];\n\n // Disable current element and section zero.\n const currentElement = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-id='${sectionId}']`);\n this._disableLink(currentElement);\n const generalSection = modalBody.querySelector(`${this.selectors.SECTIONLINK}[data-number='0']`);\n this._disableLink(generalSection);\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('sectionMove', [sectionId], target.dataset.id);\n this._destroyModal(modal, editTools);\n });\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 cmId = target.dataset.id;\n if (!cmId) {\n return;\n }\n const cmInfo = this.reactive.get('cm', cmId);\n\n event.preventDefault();\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\n // Add the target cm info.\n data.cmid = cmInfo.id;\n data.cmname = cmInfo.name;\n\n // Build the modal parameters from the event data.\n const modalParams = {\n title: getString('movecoursemodule', 'core'),\n body: Templates.render('core_courseformat/local/content/movecm', data),\n };\n\n // Create the modal.\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n const modalBody = getList(modal.getBody())[0];\n\n // Disable current element.\n let currentElement = modalBody.querySelector(`${this.selectors.CMLINK}[data-id='${cmId}']`);\n this._disableLink(currentElement);\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 int this code can be replaced when MDL-71979 is integrated.\n const sectionnode = currentElement.closest(this.selectors.SECTIONNODE);\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 jQuery(`#${collapsibleId}`).collapse('toggle');\n }\n\n // Capture click.\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 // Get draggable data from cm or section to dispatch.\n let targetSectionId;\n let targetCmId;\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\n this.reactive.dispatch('cmMove', [cmId], targetSectionId, targetCmId);\n this._destroyModal(modal, editTools);\n });\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 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 // Check we have an id.\n const sectionId = target.dataset.id;\n\n if (!sectionId) {\n return;\n }\n const sectionInfo = this.reactive.get('section', sectionId);\n\n event.preventDefault();\n\n const cmList = sectionInfo.cmlist ?? [];\n if (cmList.length || sectionInfo.hassummary || sectionInfo.rawtitle) {\n // We need confirmation if the section has something.\n const modalParams = {\n title: getString('confirm', 'core'),\n body: getString('confirmdeletesection', 'moodle', sectionInfo.title),\n saveButtonText: getString('delete', 'core'),\n type: ModalFactory.types.SAVE_CANCEL,\n };\n\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n modal.getRoot().on(\n ModalEvents.save,\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('sectionDelete', [sectionId]);\n }\n );\n return;\n } else {\n // We don't need confirmation to delete empty sections.\n this.reactive.dispatch('sectionDelete', [sectionId]);\n }\n }\n\n /**\n * Handle a toggle cm selection.\n *\n * @param {Element} target the dispatch action element\n */\n async _requestToggleSelectionCm(target) {\n const cmId = target.dataset.id;\n if (!cmId) {\n return;\n }\n const value = target.checked ?? false;\n const mutation = (value) ? 'cmSelect' : 'cmUnselect';\n this.reactive.dispatch(mutation, [cmId]);\n }\n\n /**\n * Handle a toggle section selection.\n *\n * @param {Element} target the dispatch action element\n */\n async _requestToggleSelectionSection(target) {\n const sectionId = target.dataset.id;\n if (!sectionId) {\n return;\n }\n const value = target.checked ?? false;\n const mutation = (value) ? 'sectionSelect' : 'sectionUnselect';\n this.reactive.dispatch(mutation, [sectionId]);\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) {\n return;\n }\n event.preventDefault();\n this.reactive.dispatch(mutationName, [target.dataset.id]);\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 cmId = target.dataset.id;\n if (!cmId) {\n return;\n }\n const sectionId = target.dataset.sectionid ?? null;\n event.preventDefault();\n this.reactive.dispatch('cmDuplicate', [cmId], 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 // Check we have an id.\n const cmId = target.dataset.id;\n\n if (!cmId) {\n return;\n }\n const cmInfo = this.reactive.get('cm', cmId);\n\n event.preventDefault();\n\n const modalParams = {\n title: getString('confirm', 'core'),\n body: getString(\n 'deletechecktypename',\n 'moodle',\n {\n type: cmInfo.modname,\n name: cmInfo.name,\n }\n ),\n saveButtonText: getString('delete', 'core'),\n type: ModalFactory.types.SAVE_CANCEL,\n };\n\n const modal = await this._modalBodyRenderedPromise(modalParams);\n\n modal.getRoot().on(\n ModalEvents.save,\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', [cmId]);\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 modalParams = {\n title: getString('availability', 'core'),\n body: Templates.render('core_courseformat/local/content/cm/availabilitymodal', data),\n saveButtonText: getString('apply', 'core'),\n type: ModalFactory.types.SAVE_CANCEL,\n };\n const modal = await this._modalBodyRenderedPromise(modalParams);\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 // Show the availability modal to decide which action to trigger.\n const modalParams = {\n title: getString('availability', 'core'),\n body: Templates.render('core_courseformat/local/content/section/availabilitymodal', []),\n saveButtonText: getString('apply', 'core'),\n type: ModalFactory.types.SAVE_CANCEL,\n };\n const modal = await this._modalBodyRenderedPromise(modalParams);\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.ADDSECTION);\n targets.forEach(element => {\n element.classList.toggle(this.classes.DISABLED, locked);\n this.setElementLocked(element, 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.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 {object} modalParams the modal params\n * @return {Promise} the modal body ready promise\n */\n _modalBodyRenderedPromise(modalParams) {\n return new Promise((resolve, reject) => {\n ModalFactory.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 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","BaseComponent","create","name","selectors","ACTIONLINK","SECTIONLINK","CMLINK","SECTIONNODE","MODALTOGGLER","ADDSECTION","CONTENTTREE","ACTIONMENU","ACTIONMENUTOGGLER","OPTIONSRADIO","classes","DISABLED","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","sectionId","sectionInfo","editTools","_getClosestActionMenuToogler","data","getExporter","sectionid","sectiontitle","title","modalParams","body","Templates","render","modal","_modalBodyRenderedPromise","modalBody","getBody","currentElement","querySelector","_disableLink","generalSection","ContentTree","SECTION","TOGGLER","COLLAPSE","matches","for","getAttribute","dispatch","_destroyModal","cmId","cmInfo","exporter","cmid","cmname","ENTER","sectionnode","toggler","find","collapsibleId","attr","replace","collapse","targetSectionId","targetCmId","dropData","cmDraggableData","nextcmid","section","cmlist","hassummary","rawtitle","saveButtonText","type","ModalFactory","types","SAVE_CANCEL","getRoot","on","ModalEvents","save","e","destroy","mutation","checked","mutationName","modname","cmIds","allowstealth","canUseStealth","_setupMutationRadioButtonModal","sectionIds","setButtonDisabled","submitFunction","radio","value","querySelectorAll","forEach","parentNode","dbClickEvent","locked","getElements","toggle","setElementLocked","style","pointerEvents","userSelect","add","setAttribute","Promise","resolve","reject","then","setRemoveOnClose","bodyRendered","setSaveButtonText","show","catch","hide","pendingDestroy","Pending","focus","setTimeout","actionMenu"],"mappings":"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"}