MDL-66893 mod_forum: update navigation bar in grader UI
[moodle.git] / mod / forum / amd / src / grades / grader.js
CommitLineData
bae67469
MM
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/grades/grader
20 * @package mod_forum
21 * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24import * as Selectors from './grader/selectors';
25import Repository from 'mod_forum/repository';
26import Templates from 'core/templates';
27import * as Grader from '../local/grades/grader';
28import Notification from 'core/notification';
29import CourseRepository from 'core_course/repository';
4c98e56c 30import {relativeUrl} from 'core/url';
bae67469
MM
31
32const templateNames = {
33 contentRegion: 'mod_forum/grades/grader/discussion/posts',
34};
35
046ebd3a
MM
36/**
37 * Curried function with CMID set, this is then used in unified grader as a fetch a users content.
38 *
39 * @param {Number} cmid
40 * @return {Function}
41 */
42const getContentForUserIdFunction = (cmid) => (userid) => {
43 /**
44 * Given the parent function is called with the second param set execute the partially executed function.
45 *
46 * @param {Number} userid
47 */
48 return Repository.getDiscussionByUserID(userid, cmid)
49 .then(context => {
50 // Rebuild the returned data for the template.
51 context.discussions = context.discussions.map(discussionPostMapper);
52
53 return Templates.render(templateNames.contentRegion, context);
54 })
55 .catch(Notification.exception);
56};
bae67469 57
046ebd3a
MM
58/**
59 * Curried function with CMID set, this is then used in unified grader as a fetch users call.
60 * The function curried fetches all users in a course for a given CMID.
61 *
62 * @param {Number} cmid
63 * @return {Array} Array of users for a given context.
64 */
65const getUsersForCmidFunction = (cmid) => async() => {
66 const context = await CourseRepository.getUsersFromCourseModuleID(cmid);
bae67469 67
046ebd3a 68 return context.users;
bae67469
MM
69};
70
bae67469 71
046ebd3a
MM
72const findGradableNode = node => node.closest(Selectors.gradableItem);
73
74/**
75 * For a discussion we need to manipulate it's posts to hide certain UI elements.
76 *
77 * @param {Object} discussion
78 * @return {Array} name, id, posts
79 */
80const discussionPostMapper = (discussion) => {
bae67469
MM
81 // Map postid => post.
82 const parentMap = new Map();
83 discussion.posts.parentposts.forEach(post => parentMap.set(post.id, post));
bae67469
MM
84 const userPosts = discussion.posts.userposts.map(post => {
85 post.subject = null;
86 post.readonly = true;
87 post.starter = !post.parentid;
88 post.parent = parentMap.get(post.parentid);
046ebd3a 89 post.html.rating = null;
bae67469
MM
90
91 return post;
92 });
93
94 return {
95 id: discussion.id,
96 name: discussion.name,
97 posts: userPosts,
98 };
99};
100
eaee6477
AN
101/**
102 * Launch the Grader.
103 *
104 * @param {HTMLElement} rootNode the root HTML element describing what is to be graded
105 */
046ebd3a 106const launchWholeForumGrading = async(rootNode) => {
eaee6477 107 const data = rootNode.dataset;
eaee6477
AN
108 const gradingPanelFunctions = await Grader.getGradingPanelFunctions(
109 'mod_forum',
110 data.contextid,
111 data.gradingComponent,
112 data.gradingComponentSubtype,
113 data.gradableItemtype
114 );
115
116 await Grader.launch(
046ebd3a
MM
117 getUsersForCmidFunction(data.cmid),
118 getContentForUserIdFunction(data.cmid),
eaee6477
AN
119 gradingPanelFunctions.getter,
120 gradingPanelFunctions.setter,
121 {
122 groupid: data.groupid,
123 initialUserId: data.initialuserid,
4c98e56c
RW
124 moduleName: data.name,
125 courseName: data.courseName,
126 courseUrl: relativeUrl('/course/view.php', {id: data.courseId})
eaee6477
AN
127 }
128 );
129};
130
f281c616
AN
131/**
132 * Register listeners to launch the grading panel.
133 */
bae67469 134export const registerLaunchListeners = () => {
046ebd3a 135 document.addEventListener('click', async(e) => {
bae67469
MM
136 if (e.target.matches(Selectors.launch)) {
137 const rootNode = findGradableNode(e.target);
138
139 if (!rootNode) {
140 throw Error('Unable to find a gradable item');
141 }
142
143 if (rootNode.matches(Selectors.gradableItems.wholeForum)) {
f281c616
AN
144 // Note: The preventDefault must be before any async function calls because the function becomes async
145 // at that point and the default action is implemented.
bae67469 146 e.preventDefault();
eaee6477
AN
147 try {
148 await launchWholeForumGrading(rootNode);
149 } catch (error) {
150 Notification.exception(error);
151 }
bae67469
MM
152 } else {
153 throw Error('Unable to find a valid gradable item');
154 }
155 }
156 });
157};