Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | 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
 * Collapse or expand all form sections on clicking the expand all / collapse al link.
18
 *
19
 * @module core_form/collapsesections
20
 * @copyright 2021 Bas Brands
21
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 * @since 4.0
23
 */
24
 
1441 ariadna 25
import Collapse from 'theme_boost/bootstrap/collapse';
1 efrain 26
import Pending from 'core/pending';
27
 
28
const SELECTORS = {
29
    FORM: '.mform',
30
    FORMHEADER: '.fheader',
31
    FORMCONTAINER: 'fieldset > .fcontainer',
32
};
33
 
34
const CLASSES = {
35
    SHOW: 'show',
36
    COLLAPSED: 'collapsed',
37
    HIDDEN: 'd-none'
38
};
39
 
40
/**
41
 * Initialises the form section collapse / expand action.
42
 *
43
 * @param {string} collapsesections the collapse/expand link id.
44
 */
45
export const init = collapsesections => {
46
    const pendingPromise = new Pending('core_form/collapsesections');
47
    const collapsemenu = document.querySelector(collapsesections);
48
 
49
    const formParent = collapsemenu.closest(SELECTORS.FORM);
50
    const formContainers = formParent.querySelectorAll(SELECTORS.FORMCONTAINER);
1441 ariadna 51
    [...formContainers].map(formContainer => new Collapse(formContainer, {toggle: false}));
1 efrain 52
 
53
    collapsemenu.addEventListener('keydown', e => {
54
        if (e.key === 'Enter' || e.key === ' ') {
55
            e.preventDefault();
56
            collapsemenu.click();
57
        }
58
    });
59
 
60
    // Override default collapse class if all visible containers are expanded on page load
61
    let formcontainercount = 0;
62
    let expandedcount = 0;
63
    formContainers.forEach(container => {
64
        const parentFieldset = container.parentElement;
65
        if (!parentFieldset.classList.contains(CLASSES.HIDDEN)) {
66
            formcontainercount++;
67
        }
68
        if (container.classList.contains(CLASSES.SHOW)) {
69
            expandedcount++;
70
        }
71
    });
72
 
73
    if (formcontainercount === expandedcount) {
74
        collapsemenu.classList.remove(CLASSES.COLLAPSED);
75
        collapsemenu.setAttribute('aria-expanded', true);
76
    }
77
 
78
    // When the collapse menu is toggled, update each form container to match.
79
    collapsemenu.addEventListener('click', () => {
80
        if (collapsemenu.classList.contains(CLASSES.COLLAPSED)) {
1441 ariadna 81
            const pendingPromiseToggle = new Pending('core_form/collapsesections:toggle-on');
82
            formContainers.forEach((container, index, array) => {
83
                Collapse.getInstance(container).show();
84
                if (index === array.length - 1) {
85
                    pendingPromiseToggle.resolve();
86
                }
87
            });
88
        } else {
89
            const pendingPromiseToggle = new Pending('core_form/collapsesections:toggle-off');
90
            formContainers.forEach((container, index, array) => {
91
                Collapse.getInstance(container).hide();
92
                if (index === array.length - 1) {
93
                    pendingPromiseToggle.resolve();
94
                }
95
            });
1 efrain 96
        }
97
    });
98
 
99
    // Ensure collapse menu button adds aria-controls attribute referring to each collapsible element.
100
    const collapseElements = formParent.querySelectorAll(SELECTORS.FORMHEADER);
101
    const collapseElementIds = [...collapseElements].map((element, index) => {
102
        element.id = element.id || `collapseElement-${index}`;
103
        return element.id;
104
    });
105
    collapsemenu.setAttribute('aria-controls', collapseElementIds.join(' '));
106
 
107
    // When any form container is toggled, re-calculate collapse menu state.
1441 ariadna 108
    const collapseTriggerList = document.querySelectorAll(SELECTORS.FORMCONTAINER);
109
    [...collapseTriggerList].forEach(collapseTriggerEl => {
110
        collapseTriggerEl.addEventListener('hidden.bs.collapse', () => {
111
            const allCollapsed = [...formContainers].every(container => !container.classList.contains(CLASSES.SHOW));
112
            if (allCollapsed) {
113
                collapsemenu.classList.add(CLASSES.COLLAPSED);
114
                collapsemenu.setAttribute('aria-expanded', false);
115
            }
116
        });
117
        collapseTriggerEl.addEventListener('shown.bs.collapse', () => {
118
            const allExpanded = [...formContainers].every(container => container.classList.contains(CLASSES.SHOW));
119
            if (allExpanded) {
120
                collapsemenu.classList.remove(CLASSES.COLLAPSED);
121
                collapsemenu.setAttribute('aria-expanded', true);
122
            }
123
        });
1 efrain 124
    });
125
    pendingPromise.resolve();
126
};