mod/quiz/report/overview/amd/src/regrade_modal.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/>.

/**
 * Regrade modal form is used to regrade or dryrun the attempts and questions.
 *
 * @module quiz_overview/regrade_modal
 * @copyright 2024 The Open University
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

import Modal from 'core/modal';
import Templates from 'core/templates';
import {getString} from 'core/str';
import Notification from 'core/notification';

/**
 * @type {Object} selectors used in this code.
 */
const SELECTORS = {
    'allQuestionsButton': '#regradeallquestions',
    'dryRunButton': '#dryrunbutton',
    'mainTableForm': '#attemptsform',
    'questionCheckbox': '[id^="regradeslot"]',
    'regradeAttemptsButtonId': 'regradeattempts',
    'regradeButton': '#regradebutton',
    'reportTableSelectedAttempts': '[id^="attemptid_"]:checked',
};

/**
 * Show the regrade modal.
 *
 * @param {Event} e click event that opened the modal.
 * @returns {Promise<void>}
 */
const showModal = async(e) => {
    e.preventDefault();
    try {
        let hiddenInputs = [];
        document.querySelectorAll(SELECTORS.mainTableForm + ' input[type=hidden]').forEach((hiddenInput) => {
            hiddenInputs.push({'name': hiddenInput.name, 'value': hiddenInput.value});
        });
        document.querySelectorAll(SELECTORS.reportTableSelectedAttempts).forEach((selectedAttempt) => {
            hiddenInputs.push({'name': selectedAttempt.name, 'value': selectedAttempt.value});
        });
        const modal = await Modal.create({
            title: getString('regrade', 'quiz_overview'),
            body: Templates.render('quiz_overview/regrade_modal_body', {
                'actionurl': document.querySelector(SELECTORS.mainTableForm).action,
                'hasselectedattempts': document.querySelector(SELECTORS.reportTableSelectedAttempts) !== null,
                'questions': JSON.parse(document.getElementById(SELECTORS.regradeAttemptsButtonId).dataset.slots),
                'hiddeninputs': hiddenInputs,
            }),
            isVerticallyCentered: true,
            removeOnClose: true,
            show: true,
        });
        modal.getRoot()[0].addEventListener('change', updateButtonStates);
        modal.getBodyPromise().then(updateButtonStates).catch(Notification.exception);

        // TODO MDL-82204 - there is not currently a good way to add a help icon to a modal overall, so we do it this way.
        modal.getTitlePromise().then((title) => {
            title.append(' ' + document.getElementById(SELECTORS.regradeAttemptsButtonId).dataset.helpIcon);
            // The next line is necessary to get a nice layout of the help icon.
            title[0].querySelector('a').classList.add('align-baseline');
            return title[0];
        }).catch(Notification.exception);
    } catch (ex) {
        await Notification.exception(ex);
    }
};

/**
 * Enables and disables controls when the selected options are changed.
 */
const updateButtonStates = () => {
    const allQuestionsButton = document.querySelector(SELECTORS.allQuestionsButton);

    // Question checkboxes enabled only if Selected questions is checked.
    document.querySelectorAll(SELECTORS.questionCheckbox).forEach((questionCheckbox) => {
        questionCheckbox.disabled = allQuestionsButton.checked;
    });

    // State of submit buttons.
    const isAnyQuestionSelected = document.querySelector(SELECTORS.questionCheckbox + ':checked') !== null;
    const canSubmit = allQuestionsButton.checked || isAnyQuestionSelected;
    document.querySelector(SELECTORS.regradeButton).disabled = !canSubmit;
    document.querySelector(SELECTORS.dryRunButton).disabled = !canSubmit;
};

/**
 * Initialize the regrade button to open the modal.
 */
export const init = () => {
    const regradeButton = document.getElementById(SELECTORS.regradeAttemptsButtonId);
    if (!regradeButton) {
        return;
    }

    regradeButton.addEventListener('click', showModal);
};