AutorÃa | Ultima modificación | Ver Log |
// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** This module will tie together all of the different calls the gradable module will make.** @module mod_forum/grades/grader* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/import * as Selectors from './grader/selectors';import Repository from 'mod_forum/repository';import Templates from 'core/templates';import * as Grader from '../local/grades/grader';import Notification from 'core/notification';import CourseRepository from 'core_course/repository';import {relativeUrl} from 'core/url';const templateNames = {contentRegion: 'mod_forum/grades/grader/discussion/posts',};/*** Curried function with CMID set, this is then used in unified grader as a fetch a users content.** @param {Number} cmid* @param {Bool} experimentalDisplayMode* @return {Function}*/const getContentForUserIdFunction = (cmid, experimentalDisplayMode) => (userid) => {/*** Given the parent function is called with the second param set execute the partially executed function.** @param {Number} userid*/return Repository.getDiscussionByUserID(userid, cmid).then(context => {// Rebuild the returned data for the template.context.discussions = context.discussions.map(discussionPostMapper);context.experimentaldisplaymode = experimentalDisplayMode ? true : false;return Templates.render(templateNames.contentRegion, context);}).catch(Notification.exception);};/*** Curried function with CMID set, this is then used in unified grader as a fetch users call.* The function curried fetches all users in a course for a given CMID.** @param {Number} courseID* @param {Number} groupID* @param {Boolean} onlyActive Whether to fetch only the active enrolled users or all enrolled users in the course.* @return {Array} Array of users for a given context.*/const getGradableUsersForCourseidFunction = (courseID, groupID, onlyActive) => async() => {const context = await CourseRepository.getGradableUsersFromCourseID(courseID, groupID, onlyActive);return context.users;};const findGradableNode = node => node.closest(Selectors.gradableItem);/*** For a discussion we need to manipulate it's posts to hide certain UI elements.** @param {Object} discussion* @return {Array} name, id, posts*/const discussionPostMapper = (discussion) => {// Map postid => post.const parentMap = new Map();discussion.posts.parentposts.forEach(post => parentMap.set(post.id, post));const userPosts = discussion.posts.userposts.map(post => {post.readonly = true;post.hasreplies = false;post.replies = [];const parent = post.parentid ? parentMap.get(post.parentid) : null;if (parent) {parent.hasreplies = false;parent.replies = [];parent.readonly = true;post.parentauthorname = parent.author.fullname;}return {parent,post};});return {...discussion,posts: userPosts,};};/*** Launch the Grader.** @param {HTMLElement} rootNode the root HTML element describing what is to be graded* @param {object} param* @param {bool} [param.focusOnClose=null]*/const launchWholeForumGrading = async(rootNode, {focusOnClose = null,} = {}) => {const data = rootNode.dataset;const gradingPanelFunctions = await Grader.getGradingPanelFunctions('mod_forum',data.contextid,data.gradingComponent,data.gradingComponentSubtype,data.gradableItemtype);const groupID = data.group ? data.group : 0;const onlyActive = data.gradeOnlyActiveUsers;await Grader.launch(getGradableUsersForCourseidFunction(data.courseId, groupID, onlyActive),getContentForUserIdFunction(data.cmid, data.experimentalDisplayMode == "1"),gradingPanelFunctions.getter,gradingPanelFunctions.setter,{groupid: data.groupid,initialUserId: data.initialuserid,moduleName: data.name,courseName: data.courseName,courseUrl: relativeUrl('/course/view.php', {id: data.courseId}),sendStudentNotifications: data.sendStudentNotifications,focusOnClose,});};/*** Launch the Grader.** @param {HTMLElement} rootNode the root HTML element describing what is to be graded* @param {object} param* @param {bool} [param.focusOnClose=null]*/const launchViewGrading = async(rootNode, {focusOnClose = null,} = {}) => {const data = rootNode.dataset;const gradingPanelFunctions = await Grader.getGradingPanelFunctions('mod_forum',data.contextid,data.gradingComponent,data.gradingComponentSubtype,data.gradableItemtype);await Grader.view(gradingPanelFunctions.getter,data.userid,data.name,{focusOnClose,});};/*** Register listeners to launch the grading panel.*/export const registerLaunchListeners = () => {document.addEventListener('click', async(e) => {if (e.target.matches(Selectors.launch)) {const rootNode = findGradableNode(e.target);if (!rootNode) {throw Error('Unable to find a gradable item');}if (rootNode.matches(Selectors.gradableItems.wholeForum)) {// Note: The preventDefault must be before any async function calls because the function becomes async// at that point and the default action is implemented.e.preventDefault();try {await launchWholeForumGrading(rootNode, {focusOnClose: e.target,});} catch (error) {Notification.exception(error);}} else {throw Error('Unable to find a valid gradable item');}}if (e.target.matches(Selectors.viewGrade)) {e.preventDefault();const rootNode = findGradableNode(e.target);if (!rootNode) {throw Error('Unable to find a gradable item');}if (rootNode.matches(Selectors.gradableItems.wholeForum)) {// Note: The preventDefault must be before any async function calls because the function becomes async// at that point and the default action is implemented.e.preventDefault();try {await launchViewGrading(rootNode, {focusOnClose: e.target,});} catch (error) {Notification.exception(error);}} else {throw Error('Unable to find a valid gradable item');}}});};