AutorÃa | Ultima modificación | Ver Log |
// 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/>./*** Handles edit penalty form.** @module gradepenalty_duedate/edit_penalty_form* @copyright 2024 Catalyst IT* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/import * as notification from 'core/notification';import Fragment from 'core/fragment';import Templates from 'core/templates';/*** Rule js class.*/class PenaltyRule {constructor(overdueby = 0,penalty = 0,) {this.overdueby = overdueby;this.penalty = penalty;}}/*** Selectors*/const SELECTORS = {FORM_CONTAINER: '#penalty_rule_form_container',ACTION_MENU: '.action-menu',ADD_BUTTON: '#addrulebutton',INSERT_BUTTON: '.insertbelow',DELETE_BUTTON: '.deleterulebuttons',DELETE_ALL_BUTTON_CONTAINER: '#deleteallrulesbuttoncontainer',};/*** Register click event for delete and insert buttons.*/const registerEventListeners = () => {// Find all action menus in penalty rule form.const container = document.querySelector(SELECTORS.FORM_CONTAINER);container.addEventListener('click', (e) => {if (e.target.closest(SELECTORS.DELETE_BUTTON)) {e.preventDefault();deleteRule(e.target);return;}if (e.target.closest(SELECTORS.INSERT_BUTTON)) {e.preventDefault();insertRule(e.target);return;}});document.querySelector(SELECTORS.ADD_BUTTON).addEventListener('click', (e) => {e.preventDefault();insertRuleAtIndex(container.querySelectorAll(SELECTORS.ACTION_MENU).length);return;});};/*** Delete a rule group represented by thenode.** @param {NodeElement} target*/const deleteRule = (target) => {// Get all form data.const {contextid, penaltyRules, finalPenaltyRule} = buildFormParams();const ruleNumber = getRuleNumber(target);// Remove the penalty rule.const updatedPenaltyRules = penaltyRules.filter((rule, index) => index !== ruleNumber);loadPenaltyRuleForm(contextid,updatedPenaltyRules,finalPenaltyRule,);};/*** Insert a rule group below the clicked button.** @param {NodeElement} target*/const insertRule = (target) => insertRuleAtIndex(getRuleNumber(target) + 1);/*** Add a new rule group at the specified index.** @param {Number} ruleNumber*/const insertRuleAtIndex = (ruleNumber) => {// Get all form data.const {contextid, penaltyRules, finalPenaltyRule} = buildFormParams();// Insert a new penalty rule.penaltyRules.splice(ruleNumber, 0, new PenaltyRule());loadPenaltyRuleForm(contextid,penaltyRules,finalPenaltyRule,);};/*** Get the rule number from the target.** @param {Object} target* @return {Number} rule number*/const getRuleNumber = (target) => {const allRules = target.closest(SELECTORS.FORM_CONTAINER).querySelectorAll(SELECTORS.ACTION_MENU);const foundIndex = Array.prototype.findIndex.call(allRules,(element) => element.contains(target),);if (foundIndex === -1) {throw new Error('Rule number not found on target', target);}return foundIndex;};/*** Build form parameters for loading fragment.** @return {Object} form params*/const buildFormParams = () => {// Get the penalty rule form in its container.const container = document.querySelector(SELECTORS.FORM_CONTAINER);const form = container.querySelector('form');// Get all form dataconst formData = new FormData(form);// Get context id.const contextid = formData.get('contextid');// Get group count.const groupCount = formData.get('rulegroupcount');// Create list of penalty rules.const penaltyRules = [];// Current penalty rules.for (let i = 0; i < groupCount; i++) {penaltyRules.push(new PenaltyRule(formData.get(`overdueby[${i}][number]`) * formData.get(`overdueby[${i}][timeunit]`),formData.get(`penalty[${i}]`)));}return {contextid,penaltyRules,finalPenaltyRule: formData.get('finalpenaltyrule'),};};/*** Load the penalty rule form.** @param {Number} contextId* @param {Array} penaltyRules* @param {Number} finalPenaltyRule*/const loadPenaltyRuleForm = (contextId,penaltyRules,finalPenaltyRule,) => {// Disable the form while loading to improve UX.const container = document.querySelector(SELECTORS.FORM_CONTAINER);const form = container.querySelector('form');form.querySelectorAll('input, select').forEach(input => {input.disabled = true;});// Disable the add rule button.const addButton = document.querySelector(SELECTORS.ADD_BUTTON);if (addButton) {addButton.disabled = true;}// Disable the delete all rules button.const deleteAllButton = document.querySelector(SELECTORS.DELETE_ALL_BUTTON_CONTAINER).querySelector('button');if (deleteAllButton) {deleteAllButton.disabled = true;}// Replace the form with the new form.Fragment.loadFragment('gradepenalty_duedate','penalty_rule_form',contextId,{penaltyrules: JSON.stringify(penaltyRules),finalpenaltyrule: finalPenaltyRule,},).then((html, js) => {Templates.replaceNodeContents(document.querySelector(SELECTORS.FORM_CONTAINER), html, js);if (addButton) {addButton.disabled = false;}if (deleteAllButton) {deleteAllButton.disabled = false;}return;}).catch(notification.exception);};/*** Initialize the js.*/export const init = () => {registerEventListeners();};