mod/quiz/report/overview/amd/src/regrade_modal.js

  1. // This file is part of Moodle - http://moodle.org/
  2. //
  3. // Moodle is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // Moodle is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  15. /**
  16. * Regrade modal form is used to regrade or dryrun the attempts and questions.
  17. *
  18. * @module quiz_overview/regrade_modal
  19. * @copyright 2024 The Open University
  20. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21. */
  22. import Modal from 'core/modal';
  23. import Templates from 'core/templates';
  24. import {getString} from 'core/str';
  25. import Notification from 'core/notification';
  26. /**
  27. * @type {Object} selectors used in this code.
  28. */
  29. const SELECTORS = {
  30. 'allQuestionsButton': '#regradeallquestions',
  31. 'dryRunButton': '#dryrunbutton',
  32. 'mainTableForm': '#attemptsform',
  33. 'questionCheckbox': '[id^="regradeslot"]',
  34. 'regradeAttemptsButtonId': 'regradeattempts',
  35. 'regradeButton': '#regradebutton',
  36. 'reportTableSelectedAttempts': '[id^="attemptid_"]:checked',
  37. };
  38. /**
  39. * Show the regrade modal.
  40. *
  41. * @param {Event} e click event that opened the modal.
  42. * @returns {Promise<void>}
  43. */
  44. const showModal = async(e) => {
  45. e.preventDefault();
  46. try {
  47. let hiddenInputs = [];
  48. document.querySelectorAll(SELECTORS.mainTableForm + ' input[type=hidden]').forEach((hiddenInput) => {
  49. hiddenInputs.push({'name': hiddenInput.name, 'value': hiddenInput.value});
  50. });
  51. document.querySelectorAll(SELECTORS.reportTableSelectedAttempts).forEach((selectedAttempt) => {
  52. hiddenInputs.push({'name': selectedAttempt.name, 'value': selectedAttempt.value});
  53. });
  54. const modal = await Modal.create({
  55. title: getString('regrade', 'quiz_overview'),
  56. body: Templates.render('quiz_overview/regrade_modal_body', {
  57. 'actionurl': document.querySelector(SELECTORS.mainTableForm).action,
  58. 'hasselectedattempts': document.querySelector(SELECTORS.reportTableSelectedAttempts) !== null,
  59. 'questions': JSON.parse(document.getElementById(SELECTORS.regradeAttemptsButtonId).dataset.slots),
  60. 'hiddeninputs': hiddenInputs,
  61. }),
  62. isVerticallyCentered: true,
  63. removeOnClose: true,
  64. show: true,
  65. });
  66. modal.getRoot()[0].addEventListener('change', updateButtonStates);
  67. modal.getBodyPromise().then(updateButtonStates).catch(Notification.exception);
  68. // 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.
  69. modal.getTitlePromise().then((title) => {
  70. title.append(' ' + document.getElementById(SELECTORS.regradeAttemptsButtonId).dataset.helpIcon);
  71. // The next line is necessary to get a nice layout of the help icon.
  72. title[0].querySelector('a').classList.add('align-baseline');
  73. return title[0];
  74. }).catch(Notification.exception);
  75. } catch (ex) {
  76. await Notification.exception(ex);
  77. }
  78. };
  79. /**
  80. * Enables and disables controls when the selected options are changed.
  81. */
  82. const updateButtonStates = () => {
  83. const allQuestionsButton = document.querySelector(SELECTORS.allQuestionsButton);
  84. // Question checkboxes enabled only if Selected questions is checked.
  85. document.querySelectorAll(SELECTORS.questionCheckbox).forEach((questionCheckbox) => {
  86. questionCheckbox.disabled = allQuestionsButton.checked;
  87. });
  88. // State of submit buttons.
  89. const isAnyQuestionSelected = document.querySelector(SELECTORS.questionCheckbox + ':checked') !== null;
  90. const canSubmit = allQuestionsButton.checked || isAnyQuestionSelected;
  91. document.querySelector(SELECTORS.regradeButton).disabled = !canSubmit;
  92. document.querySelector(SELECTORS.dryRunButton).disabled = !canSubmit;
  93. };
  94. /**
  95. * Initialize the regrade button to open the modal.
  96. */
  97. export const init = () => {
  98. const regradeButton = document.getElementById(SELECTORS.regradeAttemptsButtonId);
  99. if (!regradeButton) {
  100. return;
  101. }
  102. regradeButton.addEventListener('click', showModal);
  103. };