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
 * Provides the functionality for toggling the manual completion state of a course module through
18
 * the manual completion button.
19
 *
20
 * @module      core_course/manual_completion_toggle
21
 * @copyright   2021 Jun Pataleta <jun@moodle.com>
22
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
import Templates from 'core/templates';
26
import Notification from 'core/notification';
27
import {toggleManualCompletion} from 'core_course/repository';
28
import * as CourseEvents from 'core_course/events';
29
import Pending from 'core/pending';
30
 
31
/**
32
 * Selectors in the manual completion template.
33
 *
34
 * @type {{MANUAL_TOGGLE: string}}
35
 */
36
const SELECTORS = {
37
    MANUAL_TOGGLE: 'button[data-action=toggle-manual-completion]',
38
};
39
 
40
/**
41
 * Toggle type values for the data-toggletype attribute in the core_course/completion_manual template.
42
 *
43
 * @type {{TOGGLE_UNDO: string, TOGGLE_MARK_DONE: string}}
44
 */
45
const TOGGLE_TYPES = {
46
    TOGGLE_MARK_DONE: 'manual:mark-done',
47
    TOGGLE_UNDO: 'manual:undo',
48
};
49
 
50
/**
51
 * Whether the event listener has already been registered for this module.
52
 *
53
 * @type {boolean}
54
 */
55
let registered = false;
56
 
57
/**
58
 * Registers the click event listener for the manual completion toggle button.
59
 */
60
export const init = () => {
61
    if (registered) {
62
        return;
63
    }
64
    document.addEventListener('click', (e) => {
65
        const toggleButton = e.target.closest(SELECTORS.MANUAL_TOGGLE);
66
        if (toggleButton) {
67
            e.preventDefault();
68
            toggleManualCompletionState(toggleButton).catch(Notification.exception);
69
        }
70
    });
71
    registered = true;
72
};
73
 
74
/**
75
 * Toggles the manual completion state of the module for the given user.
76
 *
77
 * @param {HTMLElement} toggleButton
78
 * @returns {Promise<void>}
79
 */
80
const toggleManualCompletionState = async(toggleButton) => {
81
    const pendingPromise = new Pending('core_course:toggleManualCompletionState');
82
    // Make a copy of the original content of the button.
83
    const originalInnerHtml = toggleButton.innerHTML;
84
 
85
    // Disable the button to prevent double clicks.
86
    toggleButton.setAttribute('disabled', 'disabled');
87
 
88
    // Get button data.
89
    const toggleType = toggleButton.getAttribute('data-toggletype');
90
    const cmid = toggleButton.getAttribute('data-cmid');
91
    const activityname = toggleButton.getAttribute('data-activityname');
92
    // Get the target completion state.
93
    const completed = toggleType === TOGGLE_TYPES.TOGGLE_MARK_DONE;
94
 
95
    // Replace the button contents with the loading icon.
96
    Templates.renderForPromise('core/loading', {})
97
    .then((loadingHtml) => {
98
        Templates.replaceNodeContents(toggleButton, loadingHtml, '');
99
        return;
100
    }).catch(() => {});
101
 
102
    try {
103
        // Call the webservice to update the manual completion status.
104
        await toggleManualCompletion(cmid, completed);
105
 
106
        // All good so far. Refresh the manual completion button to reflect its new state by re-rendering the template.
107
        const templateContext = {
108
            cmid: cmid,
109
            activityname: activityname,
110
            overallcomplete: completed,
111
            overallincomplete: !completed,
112
            istrackeduser: true, // We know that we're tracking completion for this user given the presence of this button.
113
        };
114
        const renderObject = await Templates.renderForPromise('core_course/completion_manual', templateContext);
115
 
116
        // Replace the toggle button with the newly loaded template.
117
        const replacedNode = await Templates.replaceNode(toggleButton, renderObject.html, renderObject.js);
118
        const newToggleButton = replacedNode.pop();
119
 
120
        // Build manualCompletionToggled custom event.
121
        const withAvailability = toggleButton.getAttribute('data-withavailability');
122
        const toggledEvent = new CustomEvent(CourseEvents.manualCompletionToggled, {
123
            bubbles: true,
124
            detail: {
125
                cmid,
126
                activityname,
127
                completed,
128
                withAvailability,
129
            }
130
        });
131
        // Dispatch the manualCompletionToggled custom event.
132
        newToggleButton.dispatchEvent(toggledEvent);
133
 
134
    } catch (exception) {
135
        // In case of an error, revert the original state and appearance of the button.
136
        toggleButton.removeAttribute('disabled');
137
        toggleButton.innerHTML = originalInnerHtml;
138
 
139
        // Show the exception.
140
        Notification.exception(exception);
141
    }
142
    pendingPromise.resolve();
143
};