grade/report/singleview/amd/src/bulkactions.js

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Javascript module for bulk actions.
 *
 * @module      gradereport_singleview/bulkactions
 * @copyright   2022 Ilya Tregubov <ilya@moodle.com>
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

import Pending from 'core/pending';
import CustomEvents from "core/custom_interaction_events";
import ModalSaveCancel from 'core/modal_save_cancel';
import Templates from 'core/templates';
import ModalEvents from 'core/modal_events';
import * as Str from 'core/str';
import Notification from 'core/notification';
import selectors from 'gradereport_singleview/selectors';

/**
 * Initialize module.
 */
export const init = () => {
    const pendingPromise = new Pending();
    registerListenerEvents();
    pendingPromise.resolve();
};

/**
 * Register bulk actions related event listeners.
 *
 * @method registerListenerEvents
 */
const registerListenerEvents = () => {
    const events = [
        'click',
        CustomEvents.events.activate,
        CustomEvents.events.keyboardActivate
    ];
    CustomEvents.define(document, events);

    // Register events.
    events.forEach((event) => {
        document.addEventListener(event, async(e) => {
            const trigger = e.target.closest(selectors.actions.bulkaction);

            if (!trigger) {
                return;
            }
            if ((trigger.dataset.action === 'overrideallgrades') || (trigger.dataset.action === 'overridenonegrades')) {
                const override = document.querySelectorAll(selectors.elements.override);

                if (trigger.dataset.action === 'overridenonegrades') {
                    // Alert for removing all grade overrides on page.
                    Str.get_strings([
                        {key: 'removeoverride', component: 'gradereport_singleview'},
                        {key: 'overridenoneconfirm', component: 'gradereport_singleview'},
                        {key: 'removeoverridesave', component: 'gradereport_singleview'},
                        {key: 'cancel', component: 'moodle'},
                    ])
                    .then((strings) => {
                        return Notification.confirm(
                            strings[0],
                            strings[1],
                            strings[2],
                            strings[3],
                            () => {
                                // Uncheck each override checkbox - this will make grade and feedback input fields disabled.
                                override.forEach((el) => {
                                    if (el.checked) {
                                        el.click();
                                    }
                                });
                            });
                    })
                    .catch(Notification.exception);

                } else {
                    // Check each override checkbox - this will make grade and feedback input fields enabled.
                    override.forEach((el) => {
                        if (!el.checked) {
                            el.click();
                        }
                    });
                }
            } else if ((trigger.dataset.action === 'excludeallgrades') || (trigger.dataset.action === 'excludenonegrades')) {
                const exclude = document.querySelectorAll(selectors.elements.exclude);
                const checked = (trigger.dataset.action === 'excludeallgrades');
                // Uncheck or check each exclude checkbox.
                exclude.forEach((el) => {
                    el.checked = checked;
                });
            } else if (trigger.dataset.action === 'bulklegend') {
                // Modal for bulk insert grades.
                Str.get_strings([
                    {key: 'bulklegend', component: 'gradereport_singleview'},
                    {key: 'save', component: 'moodle'},
                ])
                .then((strings) => {
                    return ModalSaveCancel.create({
                        body: Templates.render('gradereport_singleview/bulkinsert', {
                            id: 'bulkinsertmodal',
                            name: 'bulkinsertmodal'
                        }),
                        title: strings[0],
                        buttons: {
                            save: strings[1],
                        },
                        removeOnClose: true,
                        show: true,
                    });
                })
                .then((modal) => {
                    modal.getFooter().find(selectors.elements.modalsave).attr('disabled', true);

                    // We need to acknowledge that we understand risks of loosing data.
                    // Only when acknowledge checkbox is checked we allow selecting insert options.
                    modal.getRoot().on('change', selectors.elements.warningcheckbox,
                        (e) => {
                            e.preventDefault();
                            if (e.target.checked) {
                                modal.getRoot().find(selectors.elements.modalformdata).removeClass('dimmed_text');
                                modal.getRoot().find(selectors.elements.modalradio).removeAttr('disabled');
                                modal.getRoot().find(selectors.elements.modalinput).removeAttr('disabled');

                                const formRadioData = modal.getRoot().find(selectors.elements.modalradiochecked).val();
                                // We allow saving grades only when all needed data present on form.
                                if (formRadioData) {
                                    modal.getFooter().find(selectors.elements.modalsave).removeAttr('disabled');
                                }
                            } else {
                                modal.getRoot().find(selectors.elements.modalformdata).addClass('dimmed_text');
                                modal.getRoot().find(selectors.elements.modalradio).attr('disabled', true);
                                modal.getRoot().find(selectors.elements.modalinput).attr('disabled', true);
                                modal.getFooter().find(selectors.elements.modalsave).attr('disabled', true);
                            }
                        });

                    // We allow saving grades only when all needed data present on form.
                    modal.getRoot().on('change', selectors.elements.modalradio, (e) => {
                            e.preventDefault();
                            modal.getFooter().find(selectors.elements.modalsave).removeAttr('disabled');
                        });

                    modal.getRoot().on(ModalEvents.save, () => {
                        // When save button is clicked in modal form we insert data from modal
                        // into preexisted hidden bulk insert form and Save button for table form.
                        document.querySelector(selectors.elements.enablebulkinsert).checked = true;
                        const formRadioData = modal.getRoot().find(selectors.elements.modalradiochecked).val();
                        const $select = document.querySelector(selectors.elements.formradio);
                        $select.value = formRadioData;

                        const formData = modal.getRoot().find(selectors.elements.modalgrade).val();
                        document.querySelector(selectors.elements.formgrade).value = formData;
                        document.querySelector(selectors.elements.formsave).click();
                    });

                    return modal;
                })
                .catch(Notification.exception);
            }
        });
    });
};