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
 * This module will tie together all of the different calls the gradable module will make.
18
 *
19
 * @module     mod_forum/local/grades/local/grader/user_picker
20
 * @copyright  2019 Mathew May <mathew.solutions>
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
import Templates from 'core/templates';
25
import Selectors from './user_picker/selectors';
26
import {getString} from 'core/str';
27
 
28
const templatePath = 'mod_forum/local/grades/local/grader';
29
 
30
/**
31
 * The Grader User Picker.
32
 *
33
 * @class mod_forum/local/grades/local/grader/user_picker
34
 */
35
class UserPicker {
36
 
37
    /**
38
     * Constructor for the User Picker.
39
     *
40
     * @constructor mod_forum/local/grades/local/grader/user_picker
41
     * @param {Array} userList List of users
42
     * @param {Function} showUserCallback The callback used to display the user
43
     * @param {Function} preChangeUserCallback The callback to use before changing user
44
     */
45
    constructor(userList, showUserCallback, preChangeUserCallback) {
46
        this.userList = userList;
47
        this.showUserCallback = showUserCallback;
48
        this.preChangeUserCallback = preChangeUserCallback;
49
        this.currentUserIndex = 0;
50
 
51
        // Ensure that render is bound correctly.
52
        this.render = this.render.bind(this);
53
        this.setUserId = this.setUserId.bind(this);
54
    }
55
 
56
    /**
57
     * Set the current userid without rendering the change.
58
     * To show the user, call showUser too.
59
     *
60
     * @param {Number} userId
61
     */
62
    setUserId(userId) {
63
        // Determine the current index based on the user ID.
64
        const userIndex = this.userList.findIndex(user => {
65
            return user.id === parseInt(userId);
66
        });
67
 
68
        if (userIndex === -1) {
69
            throw Error(`User with id ${userId} not found`);
70
        }
71
 
72
        this.currentUserIndex = userIndex;
73
    }
74
 
75
    /**
76
     * Render the user picker.
77
     */
78
    async render() {
79
        // Create the root node.
80
        this.root = document.createElement('div');
81
 
82
        const {html, js} = await this.renderNavigator();
83
        Templates.replaceNodeContents(this.root, html, js);
84
 
85
        // Call the showUser function to show the first user immediately.
86
        await this.showUser(this.currentUser);
87
 
88
        // Ensure that the event listeners are all bound.
89
        this.registerEventListeners();
90
    }
91
 
92
    /**
93
     * Render the navigator itself.
94
     *
95
     * @returns {Promise}
96
     */
97
    renderNavigator() {
98
        return Templates.renderForPromise(`${templatePath}/user_picker`, {});
99
    }
100
 
101
    /**
102
     * Render the current user details for the picker.
103
     *
104
     * @param {Object} context The data used to render the user picker.
105
     * @returns {Promise}
106
     */
107
    renderUserChange(context) {
108
        return Templates.renderForPromise(`${templatePath}/user_picker/user`, context);
109
    }
110
 
111
    /**
112
     * Show the specified user in the picker.
113
     *
114
     * @param {Object} user
115
     */
116
    async showUser(user) {
117
        const [{html, js}] = await Promise.all([this.renderUserChange(user), this.showUserCallback(user)]);
118
        const userRegion = this.root.querySelector(Selectors.regions.userRegion);
119
        Templates.replaceNodeContents(userRegion, html, js);
120
 
121
        // Update the hidden now-grading region so screen readers can announce the user that's currently being graded.
122
        const currentUserRegion = this.root.querySelector(Selectors.regions.currentUser);
123
        currentUserRegion.textContent = await getString('nowgradinguser', 'mod_forum', user.fullname);
124
    }
125
 
126
    /**
127
     * Register the event listeners for the user picker.
128
     */
129
    registerEventListeners() {
130
        this.root.addEventListener('click', async(e) => {
131
            const button = e.target.closest(Selectors.actions.changeUser);
132
 
133
            if (button) {
134
                const result = await this.preChangeUserCallback(this.currentUser);
135
 
136
                if (!result.failed) {
137
                    this.updateIndex(parseInt(button.dataset.direction));
138
                    await this.showUser(this.currentUser);
139
                }
140
            }
141
        });
142
    }
143
 
144
    /**
145
     * Update the current user index.
146
     *
147
     * @param {Number} direction
148
     * @returns {Number}}
149
     */
150
    updateIndex(direction) {
151
        this.currentUserIndex += direction;
152
 
153
        // Loop around the edges.
154
        if (this.currentUserIndex < 0) {
155
            this.currentUserIndex = this.userList.length - 1;
156
        } else if (this.currentUserIndex > this.userList.length - 1) {
157
            this.currentUserIndex = 0;
158
        }
159
 
160
        return this.currentUserIndex;
161
    }
162
 
163
    /**
164
     * Get the details of the user currently shown with the total number of users, and the 1-indexed count of the
165
     * current user.
166
     *
167
     * @returns {Object}
168
     */
169
    get currentUser() {
170
        return {
171
            ...this.userList[this.currentUserIndex],
172
            total: this.userList.length,
173
            displayIndex: this.currentUserIndex + 1,
174
        };
175
    }
176
 
177
    /**
178
     * Get the root node for the User Picker.
179
     *
180
     * @returns {HTMLElement}
181
     */
182
    get rootNode() {
183
        return this.root;
184
    }
185
}
186
 
187
/**
188
 * Create a new user picker.
189
 *
190
 * @param {Array} users The list of users
191
 * @param {Function} showUserCallback The function to call to show a specific user
192
 * @param {Function} preChangeUserCallback The fucntion to call to save the grade for the current user
193
 * @param {Number} [currentUserID] The userid of the current user
194
 * @returns {UserPicker}
195
 */
196
export default async(
197
    users,
198
    showUserCallback,
199
    preChangeUserCallback,
200
    {
201
        initialUserId = null,
202
    } = {}
203
) => {
204
    const userPicker = new UserPicker(users, showUserCallback, preChangeUserCallback);
205
    if (initialUserId) {
206
        userPicker.setUserId(initialUserId);
207
    }
208
    await userPicker.render();
209
 
210
    return userPicker;
211
};