Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

{"version":3,"file":"bulkselection.min.js","sources":["../../../../src/local/content/actions/bulkselection.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 * Bulk selection auxiliar methods.\n *\n * @module     core_courseformat/local/content/actions/bulkselection\n * @class      core_courseformat/local/content/actions/bulkselection\n * @copyright  2023 Ferran Recio <ferran@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nclass BulkSelector {\n\n    /**\n     * The class constructor.\n     * @param {CourseEditor} courseEditor the original actions component.\n     */\n    constructor(courseEditor) {\n        this.courseEditor = courseEditor;\n        this.selectors = {\n            BULKCMCHECKBOX: `[data-bulkcheckbox][data-action='toggleSelectionCm']`,\n            BULKSECTIONCHECKBOX: `[data-bulkcheckbox][data-action='toggleSelectionSection']`,\n            CONTENT: `#region-main`,\n        };\n    }\n\n    /**\n     * Process a new selection.\n     * @param {Number} id\n     * @param {String} elementType cm or section\n     * @param {Object} settings special selection settings\n     * @param {Boolean} settings.all if the action is over all elements of the same type\n     * @param {Boolean} settings.range if the action is over a range of elements\n     */\n    processNewSelection(id, elementType, settings) {\n        const value = !this._isBulkSelected(id, elementType);\n        if (settings.all && settings.range) {\n            this.switchCurrentSelection();\n            return;\n        }\n        if (!this._isSelectable(id, elementType)) {\n            return;\n        }\n        if (settings.all) {\n            if (elementType == 'cm') {\n                this._updateBulkCmSiblings(id, value);\n            } else {\n                this._updateBulkSelectionAll(elementType, value);\n            }\n            return;\n        }\n        if (settings.range) {\n            this._updateBulkSelectionRange(id, elementType, value);\n            return;\n        }\n        this._updateBulkSelection([id], elementType, value);\n    }\n\n    /**\n     * Switch between section and cm selection.\n     */\n    switchCurrentSelection() {\n        const bulk = this.courseEditor.get('bulk');\n        if (bulk.selectedType === '' || bulk.selection.length == 0) {\n            return;\n        }\n        const newSelectedType = (bulk.selectedType === 'section') ? 'cm' : 'section';\n        let newSelectedIds;\n        if (bulk.selectedType === 'section') {\n            newSelectedIds = this._getCmIdsFromSections(bulk.selection);\n        } else {\n            newSelectedIds = this._getSectionIdsFromCms(bulk.selection);\n        }\n        // Formats can display only a few activities of the section,\n        // We need to select on the activities present in the page.\n        const affectedIds = [];\n        newSelectedIds.forEach(newId => {\n            if (this._getSelector(newId, newSelectedType)) {\n                affectedIds.push(newId);\n            }\n        });\n        this.courseEditor.dispatch('bulkEnable', true);\n        if (affectedIds.length != 0) {\n            this._updateBulkSelection(affectedIds, newSelectedType, true);\n        }\n    }\n\n    /**\n     * Select all elements of the current type.\n     * @param {Boolean} value the wanted selected value\n     */\n    selectAll(value) {\n        const bulk = this.courseEditor.get('bulk');\n        if (bulk.selectedType == '') {\n            return;\n        }\n        if (!value) {\n            this.courseEditor.dispatch('bulkEnable', true);\n            return;\n        }\n        const elementType = bulk.selectedType;\n        this._updateBulkSelectionAll(elementType, value);\n    }\n\n    /**\n     * Checks if all selectable elements are selected.\n     * @returns {Boolean} true if all are selected\n     */\n    checkAllSelected() {\n        const bulk = this.courseEditor.get('bulk');\n        if (bulk.selectedType == '') {\n            return false;\n        }\n        return this._getContentCheckboxes(bulk.selectedType).every(bulkSelect => {\n            if (bulkSelect.disabled) {\n                return true;\n            }\n            // Some sections may not be selectale for bulk actions.\n            if (bulk.selectedType == 'section') {\n                const section = this.courseEditor.get('section', bulkSelect.dataset.id);\n                if (!section.bulkeditable) {\n                    return true;\n                }\n            }\n            return bulk.selection.includes(bulkSelect.dataset.id);\n        });\n    }\n\n    /**\n     * Check if the id is part of the current bulk selection.\n     * @private\n     * @param {Number} id\n     * @param {String} elementType\n     * @returns {Boolean} if the element is present in the current selection.\n     */\n    _isBulkSelected(id, elementType) {\n        const bulk = this.courseEditor.get('bulk');\n        if (bulk.selectedType !== elementType) {\n            return false;\n        }\n        return bulk.selection.includes(id);\n    }\n\n    /**\n     * Update the current bulk selection removing or adding Ids.\n     * @private\n     * @param {Number[]} ids the user selected element id\n     * @param {String} elementType cm or section\n     * @param {Boolean} value the wanted selected value\n     */\n    _updateBulkSelection(ids, elementType, value) {\n        let mutation = elementType;\n        mutation += (value) ? 'Select' : 'Unselect';\n        this.courseEditor.dispatch(mutation, ids);\n    }\n\n    /**\n     * Get all content bulk selector checkboxes of one type (section/cm).\n     * @private\n     * @param {String} elementType section or cm\n     * @returns {HTMLElement[]} an array with all checkboxes\n     */\n    _getContentCheckboxes(elementType) {\n        const selector = (elementType == 'cm') ? this.selectors.BULKCMCHECKBOX : this.selectors.BULKSECTIONCHECKBOX;\n        const checkboxes = document.querySelectorAll(`${this.selectors.CONTENT} ${selector}`);\n        // Converting to array because NodeList has less iteration methods.\n        return [...checkboxes];\n    }\n\n    /**\n     * Validate if an element is selectable in the current page.\n     * @private\n     * @param {Number} id the user selected element id\n     * @param {String} elementType cm or section\n     * @return {Boolean}\n     */\n    _isSelectable(id, elementType) {\n        const bulkSelect = this._getSelector(id, elementType);\n        if (!bulkSelect || bulkSelect.disabled) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Get as specific element checkbox.\n     * @private\n     * @param {Number} id\n     * @param {String} elementType cm or section\n     * @returns {HTMLElement|undefined}\n     */\n    _getSelector(id, elementType) {\n        let selector = (elementType == 'cm') ? this.selectors.BULKCMCHECKBOX : this.selectors.BULKSECTIONCHECKBOX;\n        selector += `[data-id='${id}']`;\n        return document.querySelector(`${this.selectors.CONTENT} ${selector}`);\n    }\n\n    /**\n     * Update the current bulk selection when a user uses shift to select a range.\n     * @private\n     * @param {Number} id the user selected element id\n     * @param {String} elementType cm or section\n     * @param {Boolean} value the wanted selected value\n     */\n    _updateBulkSelectionRange(id, elementType, value) {\n        const bulk = this.courseEditor.get('bulk');\n        let lastSelectedId = bulk.selection.at(-1);\n        if (bulk.selectedType !== elementType || lastSelectedId == id) {\n            this._updateBulkSelection([id], elementType, value);\n            return;\n        }\n        const affectedIds = [];\n        let found = 0;\n        this._getContentCheckboxes(elementType).every(bulkSelect => {\n            if (bulkSelect.disabled) {\n                return true;\n            }\n            if (elementType == 'section') {\n                const section = this.courseEditor.get('section', bulkSelect.dataset.id);\n                if (value && !section?.bulkeditable) {\n                    return true;\n                }\n            }\n            if (bulkSelect.dataset.id == id || bulkSelect.dataset.id == lastSelectedId) {\n                found++;\n            }\n            if (found == 0) {\n                return true;\n            }\n            affectedIds.push(bulkSelect.dataset.id);\n            return found != 2;\n        });\n        this._updateBulkSelection(affectedIds, elementType, value);\n    }\n\n    /**\n     * Select or unselect all cm siblings.\n     * @private\n     * @param {Number} cmId the user selected element id\n     * @param {Boolean} value the wanted selected value\n     */\n    _updateBulkCmSiblings(cmId, value) {\n        const bulk = this.courseEditor.get('bulk');\n        if (bulk.selectedType === 'section') {\n            return;\n        }\n        const cm = this.courseEditor.get('cm', cmId);\n        const section = this.courseEditor.get('section', cm.sectionid);\n        // Formats can display only a few activities of the section,\n        // We need to select on the activities selectable in the page.\n        const affectedIds = [];\n        section.cmlist.forEach(sectionCmId => {\n            if (this._isSelectable(sectionCmId, 'cm')) {\n                affectedIds.push(sectionCmId);\n            }\n        });\n        this._updateBulkSelection(affectedIds, 'cm', value);\n    }\n\n    /**\n     * Select or unselects al elements of the same type.\n     * @private\n     * @param {String} elementType section or cm\n     * @param {Boolean} value if the elements must be selected or unselected.\n     */\n    _updateBulkSelectionAll(elementType, value) {\n        const affectedIds = [];\n        this._getContentCheckboxes(elementType).forEach(bulkSelect => {\n            if (bulkSelect.disabled) {\n                return;\n            }\n            if (elementType == 'section') {\n                const section = this.courseEditor.get('section', bulkSelect.dataset.id);\n                if (value && !section?.bulkeditable) {\n                    return;\n                }\n            }\n            affectedIds.push(bulkSelect.dataset.id);\n        });\n        this._updateBulkSelection(affectedIds, elementType, value);\n    }\n\n    /**\n     * Get all cm ids from a specific section ids.\n     * @private\n     * @param {Number[]} sectionIds\n     * @returns {Number[]} the cm ids\n     */\n    _getCmIdsFromSections(sectionIds) {\n        const result = [];\n        sectionIds.forEach(sectionId => {\n            const section = this.courseEditor.get('section', sectionId);\n            result.push(...section.cmlist);\n        });\n        return result;\n    }\n\n    /**\n     * Get all section ids containing a specific cm ids.\n     * @private\n     * @param {Number[]} cmIds\n     * @returns {Number[]} the section ids\n     */\n    _getSectionIdsFromCms(cmIds) {\n        const result = new Set();\n        cmIds.forEach(cmId => {\n            const cm = this.courseEditor.get('cm', cmId);\n            if (cm.sectionnumber == 0) {\n                return;\n            }\n            result.add(cm.sectionid);\n        });\n        return [...result];\n    }\n}\n\n/**\n * Process a bulk selection toggle action.\n * @method\n * @param {CourseEditor} courseEditor\n * @param {HTMLElement} target the action element\n * @param {Event} event\n * @param {String} elementType cm or section\n */\nexport const toggleBulkSelectionAction = function(courseEditor, target, event, elementType) {\n    const id = target.dataset.id;\n    if (!id) {\n        return;\n    }\n    // When the action cames from a form element (checkbox) we should not preventDefault.\n    // If we do it the changechecker module will execute the state change twice.\n    if (target.dataset.preventDefault) {\n        event.preventDefault();\n    }\n    // Using shift or alt key can produce text selection.\n    document.getSelection().removeAllRanges();\n\n    const bulkSelector = new BulkSelector(courseEditor);\n    bulkSelector.processNewSelection(\n        id,\n        elementType,\n        {\n            range: event.shiftKey,\n            all: event.altKey,\n        }\n    );\n};\n\n/**\n * Switch the current bulk selection.\n * @method\n * @param {CourseEditor} courseEditor\n */\nexport const switchBulkSelection = function(courseEditor) {\n    const bulkSelector = new BulkSelector(courseEditor);\n    bulkSelector.switchCurrentSelection();\n};\n\n/**\n * Select/unselect all element of the selected type.\n * @method\n * @param {CourseEditor} courseEditor\n * @param {Boolean} value if the elements must be selected or unselected.\n */\nexport const selectAllBulk = function(courseEditor, value) {\n    const bulkSelector = new BulkSelector(courseEditor);\n    bulkSelector.selectAll(value);\n};\n\n/**\n * Check if all possible elements are selected.\n * @method\n * @param {CourseEditor} courseEditor\n * @return {Boolean} if all elements of the current type are selected.\n */\nexport const checkAllBulkSelected = function(courseEditor) {\n    const bulkSelector = new BulkSelector(courseEditor);\n    return bulkSelector.checkAllSelected();\n};\n"],"names":["BulkSelector","constructor","courseEditor","selectors","BULKCMCHECKBOX","BULKSECTIONCHECKBOX","CONTENT","processNewSelection","id","elementType","settings","value","this","_isBulkSelected","all","range","switchCurrentSelection","_isSelectable","_updateBulkCmSiblings","_updateBulkSelectionAll","_updateBulkSelectionRange","_updateBulkSelection","bulk","get","selectedType","selection","length","newSelectedType","newSelectedIds","_getCmIdsFromSections","_getSectionIdsFromCms","affectedIds","forEach","newId","_getSelector","push","dispatch","selectAll","checkAllSelected","_getContentCheckboxes","every","bulkSelect","disabled","dataset","bulkeditable","includes","ids","mutation","selector","document","querySelectorAll","querySelector","lastSelectedId","at","found","section","cmId","cm","sectionid","cmlist","sectionCmId","sectionIds","result","sectionId","cmIds","Set","sectionnumber","add","target","event","preventDefault","getSelection","removeAllRanges","shiftKey","altKey"],"mappings":"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"}