Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
/**
17
 * Javascript module for toggling the visibility of the grade categories in the user report.
18
 *
19
 * @module    gradereport_user/gradecategorytoggle
20
 * @copyright 2022 Mihail Geshoski <mihail@moodle.com>
21
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
const SELECTORS = {
25
    CATEGORY_TOGGLE: '.toggle-category',
26
    USER_REPORT_TABLE: '.user-grade'
27
};
28
 
29
/**
30
 * Register related event listeners.
31
 *
32
 * @method registerListenerEvents
33
 * @param {string} userReportId The ID of the user report container element.
34
 */
35
const registerListenerEvents = (userReportId) => {
36
    const reportContainer = document.querySelector('#' + userReportId);
37
    const userReport = reportContainer.querySelector(SELECTORS.USER_REPORT_TABLE);
38
 
39
    userReport.addEventListener('click', e => {
40
        const toggle = e.target.closest(SELECTORS.CATEGORY_TOGGLE);
41
 
42
        if (toggle) {
43
            e.preventDefault();
44
            toggleCategory(toggle);
45
        }
46
    });
47
};
48
 
49
/**
50
 * Method that handles the category toggle action.
51
 *
52
 * @method toggleCategory
53
 * @param {object} toggleElement The category toggle node that was clicked.
54
 */
55
const toggleCategory = (toggleElement) => {
56
    const target = toggleElement.dataset.target;
57
    const categoryId = toggleElement.dataset.categoryid;
58
    // Whether the toggle action is collapsing the category or not.
59
    const isCollapsing = toggleElement.getAttribute('aria-expanded') === "true";
60
    const userReport = toggleElement.closest(SELECTORS.USER_REPORT_TABLE);
61
 
62
    // Find all targeted 'children' rows of the toggled category.
63
    const targetRows = userReport.querySelectorAll(target);
64
 
65
    if (isCollapsing) {
66
        toggleElement.setAttribute('aria-expanded', 'false');
67
        // Update the 'data-target' of the toggle category node to make sure that when we perform another toggle action
68
        // to expand this category we only target rows which have been hidden by this category toggle action.
69
        toggleElement.dataset.target = `[data-hidden-by='${categoryId}']`;
70
    } else {
71
        toggleElement.setAttribute('aria-expanded', 'true');
72
        // Update the 'data-target' of the toggle category node to make sure that when we perform another toggle action
73
        // to collapse this category we only target rows which are children of this category and are not currently hidden.
74
        toggleElement.dataset.target = `.cat_${categoryId}[data-hidden='false']`;
75
    }
76
 
77
    // Loop through all targeted children row elements and update the required data attributes to either hide or show
78
    // them depending on the toggle action (collapsing or expanding).
79
    targetRows.forEach((row) => {
80
        if (isCollapsing) {
81
            row.dataset.hidden = 'true';
82
            row.dataset.hiddenBy = categoryId;
83
        } else {
84
            row.dataset.hidden = 'false';
85
            row.dataset.hiddenBy = '';
86
        }
87
    });
88
 
89
    // Since the user report is presented in an HTML table, rowspans are used under each category to create a visual
90
    // hierarchy between categories and grading items. When expanding or collapsing a category we need to also update
91
    // (subtract or add) the rowspan values associated to each parent category row to preserve the correct visual
92
    // hierarchy in the table.
93
    updateParentCategoryRowspans(toggleElement, targetRows.length);
94
};
95
 
96
/**
97
 * Method that updates the rowspan value of all 'parent' category rows of a given category node.
98
 *
99
 * @method updateParentCategoryRowspans
100
 * @param {object} toggleElement The category toggle node that was clicked.
101
 * @param {int} num The number we want to add or subtract from the rowspan value of the 'parent' category row elements.
102
 */
103
const updateParentCategoryRowspans = (toggleElement, num) => {
104
    const userReport = toggleElement.closest(SELECTORS.USER_REPORT_TABLE);
105
    // Get the row element which contains the category toggle node.
106
    const rowElement = toggleElement.closest('tr');
107
 
108
    // Loop through the class list of the toggle category row element.
109
    // The list contains classes which identify all parent categories of the toggled category.
110
    rowElement.classList.forEach((className) => {
111
        // Find the toggle node of the 'parent' category that is identified by the given class name.
112
        const parentCategoryToggleElement = userReport.querySelector(`[data-target=".${className}[data-hidden='false']"`);
113
        if (parentCategoryToggleElement) {
114
            // Get the row element which contains the parent category toggle node.
115
            const categoryRowElement = parentCategoryToggleElement.closest('tr');
116
            // Find the rowspan element associated to this parent category.
117
            const categoryRowSpanElement = categoryRowElement.nextElementSibling.querySelector('[rowspan]');
118
 
119
            // Depending on whether the toggle action has expanded or collapsed the category, either add or
120
            // subtract from the 'parent' category rowspan.
121
            if (toggleElement.getAttribute('aria-expanded') === "true") {
122
                categoryRowSpanElement.rowSpan = categoryRowSpanElement.rowSpan + num;
123
            } else { // The category has been collapsed.
124
                categoryRowSpanElement.rowSpan = categoryRowSpanElement.rowSpan - num;
125
            }
126
        }
127
    });
128
};
129
 
130
/**
131
 * Init method.
132
 *
133
 * @param {string} userReportId The ID of the user report container element.
134
 */
135
export const init = (userReportId) => {
136
    registerListenerEvents(userReportId);
137
};