diff --git a/mod/forum/amd/build/local/grades/grader.min.js b/mod/forum/amd/build/local/grades/grader.min.js index b2cfa92eb6d09..5ee007bba2c25 100644 --- a/mod/forum/amd/build/local/grades/grader.min.js +++ b/mod/forum/amd/build/local/grades/grader.min.js @@ -1,2 +1,2 @@ -define ("mod_forum/local/grades/grader",["exports","core/templates","./local/grader/selectors","./local/grader/user_picker","mod_forum/local/layout/fullscreen","./local/grader/gradingpanel"],function(a,b,c,d,e,f){"use strict";Object.defineProperty(a,"__esModule",{value:!0});Object.defineProperty(a,"getGradingPanelFunctions",{enumerable:!0,get:function get(){return f.default}});a.launch=void 0;b=g(b);c=g(c);d=function(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}(d);f=g(f);function g(a){return a&&a.__esModule?a:{default:a}}function h(a,b){return l(a)||k(a,b)||j()}function j(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function k(a,b){var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function l(a){if(Array.isArray(a))return a}function m(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function n(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){m(h,d,e,f,g,"next",a)}function g(a){m(h,d,e,f,g,"throw",a)}f(void 0)})}}var o={grader:{app:"mod_forum/local/grades/grader"}},p=function(a,d){var e=a.querySelector(c.default.regions.pickerRegion);b.default.replaceNodeContents(e,d,"")},q=function(a,b){return[a,b]},r=function(a,d,e){return function(){var f=n(regeneratorRuntime.mark(function f(g){var i,j,k,l,m,n,o,p,r,s;return regeneratorRuntime.wrap(function(f){while(1){switch(f.prev=f.next){case 0:f.next=2;return Promise.all([d(g.id).then(q),e(g.id)]);case 2:i=f.sent;j=h(i,2);k=h(j[0],2);l=k[0];m=k[1];n=j[1];b.default.replaceNodeContents(a.querySelector(c.default.regions.moduleReplace),l,m);f.next=11;return b.default.render(n.templatename,n.grade).then(q);case 11:o=f.sent;p=h(o,2);r=p[0];s=p[1];b.default.replaceNodeContents(a.querySelector(c.default.regions.gradingPanel),r,s);case 16:case"end":return f.stop();}}},f)}));return function(){return f.apply(this,arguments)}}()},s=function(a){var b=a.getContainer();b.addEventListener("click",function(b){if(b.target.closest(c.default.buttons.toggleFullscreen)){b.stopImmediatePropagation();b.preventDefault();a.toggleFullscreen()}else if(b.target.closest(c.default.buttons.closeGrader)){b.stopImmediatePropagation();b.preventDefault();a.close()}})},t=function(a,b){return function(d){return b(d.id,a.querySelector(c.default.regions.gradingPanel))}},u=function(){var a=n(regeneratorRuntime.mark(function a(c,f,g,i){var j,k,l,m,n,q,u,v,w,x,y,z,A=arguments;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:j=4.\n\n/**\n * This module will tie together all of the different calls the gradable module will make.\n *\n * @module mod_forum/local/grades/grader\n * @package mod_forum\n * @copyright 2019 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport Templates from 'core/templates';\n// TODO import Notification from 'core/notification';\nimport Selectors from './local/grader/selectors';\nimport * as UserPicker from './local/grader/user_picker';\nimport {createLayout as createFullScreenWindow} from 'mod_forum/local/layout/fullscreen';\nimport getGradingPanelFunctions from './local/grader/gradingpanel';\n\nconst templateNames = {\n grader: {\n app: 'mod_forum/local/grades/grader',\n },\n};\n\nconst displayUserPicker = (root, html) => {\n const pickerRegion = root.querySelector(Selectors.regions.pickerRegion);\n Templates.replaceNodeContents(pickerRegion, html, '');\n};\n\nconst fetchContentFromRender = (html, js) => {\n return [html, js];\n};\n\nconst getUpdateUserContentFunction = (root, getContentForUser, getGradeForUser) => {\n return async(user) => {\n const [\n [html, js],\n userGrade,\n ] = await Promise.all([\n getContentForUser(user.id).then(fetchContentFromRender),\n getGradeForUser(user.id),\n ]);\n Templates.replaceNodeContents(root.querySelector(Selectors.regions.moduleReplace), html, js);\n\n const [\n gradingPanelHtml,\n gradingPanelJS\n ] = await Templates.render(userGrade.templatename, userGrade.grade).then(fetchContentFromRender);\n Templates.replaceNodeContents(root.querySelector(Selectors.regions.gradingPanel), gradingPanelHtml, gradingPanelJS);\n };\n};\n\nconst registerEventListeners = (graderLayout) => {\n const graderContainer = graderLayout.getContainer();\n graderContainer.addEventListener('click', (e) => {\n if (e.target.closest(Selectors.buttons.toggleFullscreen)) {\n e.stopImmediatePropagation();\n e.preventDefault();\n graderLayout.toggleFullscreen();\n } else if (e.target.closest(Selectors.buttons.closeGrader)) {\n e.stopImmediatePropagation();\n e.preventDefault();\n\n graderLayout.close();\n }\n });\n};\n\nconst getSaveUserGradeFunction = (root, setGradeForUser) => {\n return user => {\n return setGradeForUser(user.id, root.querySelector(Selectors.regions.gradingPanel));\n };\n};\n\n// Make this explicit rather than object\nexport const launch = async(getListOfUsers, getContentForUser, getGradeForUser, setGradeForUser, {\n initialUserId = 0, moduleName\n} = {}) => {\n\n const [\n graderLayout,\n graderHTML,\n userList,\n ] = await Promise.all([\n createFullScreenWindow({fullscreen: false, showLoader: false}),\n Templates.render(templateNames.grader.app, {moduleName: moduleName}),\n getListOfUsers(),\n ]);\n const graderContainer = graderLayout.getContainer();\n\n Templates.replaceNodeContents(graderContainer, graderHTML, '');\n registerEventListeners(graderLayout);\n const updateUserContent = getUpdateUserContentFunction(graderContainer, getContentForUser, getGradeForUser);\n\n const pickerHTML = await UserPicker.buildPicker(\n userList,\n initialUserId,\n updateUserContent,\n getSaveUserGradeFunction(graderContainer, setGradeForUser)\n );\n\n displayUserPicker(graderContainer, pickerHTML);\n};\n\nexport {getGradingPanelFunctions};\n"],"file":"grader.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/grades/grader.js"],"names":["templateNames","grader","app","displayUserPicker","root","html","pickerRegion","querySelector","Selectors","regions","Templates","replaceNodeContents","fetchContentFromRender","js","getUpdateUserContentFunction","getContentForUser","getGradeForUser","user","Promise","all","id","then","userGrade","moduleReplace","render","templatename","grade","gradingPanelHtml","gradingPanelJS","gradingPanel","registerEventListeners","graderLayout","graderContainer","getContainer","addEventListener","e","target","closest","buttons","toggleFullscreen","stopImmediatePropagation","preventDefault","closeGrader","close","getSaveUserGradeFunction","setGradeForUser","result","addToast","launch","getListOfUsers","initialUserId","moduleName","fullscreen","showLoader","graderHTML","userList","updateUserContent","UserPicker","buildPicker","pickerHTML"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * This module will tie together all of the different calls the gradable module will make.\n *\n * @module mod_forum/local/grades/grader\n * @package mod_forum\n * @copyright 2019 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport Templates from 'core/templates';\n// TODO import Notification from 'core/notification';\nimport Selectors from './local/grader/selectors';\nimport * as UserPicker from './local/grader/user_picker';\nimport {createLayout as createFullScreenWindow} from 'mod_forum/local/layout/fullscreen';\nimport getGradingPanelFunctions from './local/grader/gradingpanel';\nimport {add as addToast} from 'core/toast';\nimport {get_string as getString} from 'core/str';\n\nconst templateNames = {\n grader: {\n app: 'mod_forum/local/grades/grader',\n },\n};\n\nconst displayUserPicker = (root, html) => {\n const pickerRegion = root.querySelector(Selectors.regions.pickerRegion);\n Templates.replaceNodeContents(pickerRegion, html, '');\n};\n\nconst fetchContentFromRender = (html, js) => {\n return [html, js];\n};\n\nconst getUpdateUserContentFunction = (root, getContentForUser, getGradeForUser) => {\n return async(user) => {\n const [\n [html, js],\n userGrade,\n ] = await Promise.all([\n getContentForUser(user.id).then(fetchContentFromRender),\n getGradeForUser(user.id),\n ]);\n Templates.replaceNodeContents(root.querySelector(Selectors.regions.moduleReplace), html, js);\n\n const [\n gradingPanelHtml,\n gradingPanelJS\n ] = await Templates.render(userGrade.templatename, userGrade.grade).then(fetchContentFromRender);\n Templates.replaceNodeContents(root.querySelector(Selectors.regions.gradingPanel), gradingPanelHtml, gradingPanelJS);\n };\n};\n\nconst registerEventListeners = (graderLayout) => {\n const graderContainer = graderLayout.getContainer();\n graderContainer.addEventListener('click', (e) => {\n if (e.target.closest(Selectors.buttons.toggleFullscreen)) {\n e.stopImmediatePropagation();\n e.preventDefault();\n graderLayout.toggleFullscreen();\n } else if (e.target.closest(Selectors.buttons.closeGrader)) {\n e.stopImmediatePropagation();\n e.preventDefault();\n\n graderLayout.close();\n }\n });\n};\n\n/**\n * Get the function used to save a user grade.\n *\n * @param {Element} root The contaienr\n * @param {Function} setGradeForUser The function that will be called.\n * @return {Function}\n */\nconst getSaveUserGradeFunction = (root, setGradeForUser) => {\n return async user => {\n try {\n const result = await setGradeForUser(user.id, root.querySelector(Selectors.regions.gradingPanel));\n addToast(await getString('grades:gradesavedfor', 'mod_forum', user));\n\n return result;\n } catch (error) {\n throw error;\n }\n };\n};\n\n// Make this explicit rather than object\nexport const launch = async(getListOfUsers, getContentForUser, getGradeForUser, setGradeForUser, {\n initialUserId = 0, moduleName\n} = {}) => {\n\n const [\n graderLayout,\n graderHTML,\n userList,\n ] = await Promise.all([\n createFullScreenWindow({fullscreen: false, showLoader: false}),\n Templates.render(templateNames.grader.app, {moduleName: moduleName}),\n getListOfUsers(),\n ]);\n const graderContainer = graderLayout.getContainer();\n\n Templates.replaceNodeContents(graderContainer, graderHTML, '');\n registerEventListeners(graderLayout);\n const updateUserContent = getUpdateUserContentFunction(graderContainer, getContentForUser, getGradeForUser);\n\n const pickerHTML = await UserPicker.buildPicker(\n userList,\n initialUserId,\n updateUserContent,\n getSaveUserGradeFunction(graderContainer, setGradeForUser)\n );\n\n displayUserPicker(graderContainer, pickerHTML);\n};\n\nexport {getGradingPanelFunctions};\n"],"file":"grader.min.js"} \ No newline at end of file diff --git a/mod/forum/amd/src/local/grades/grader.js b/mod/forum/amd/src/local/grades/grader.js index 33b2b7528abf7..26975091373cc 100644 --- a/mod/forum/amd/src/local/grades/grader.js +++ b/mod/forum/amd/src/local/grades/grader.js @@ -27,6 +27,8 @@ import Selectors from './local/grader/selectors'; import * as UserPicker from './local/grader/user_picker'; import {createLayout as createFullScreenWindow} from 'mod_forum/local/layout/fullscreen'; import getGradingPanelFunctions from './local/grader/gradingpanel'; +import {add as addToast} from 'core/toast'; +import {get_string as getString} from 'core/str'; const templateNames = { grader: { @@ -78,9 +80,23 @@ const registerEventListeners = (graderLayout) => { }); }; +/** + * Get the function used to save a user grade. + * + * @param {Element} root The contaienr + * @param {Function} setGradeForUser The function that will be called. + * @return {Function} + */ const getSaveUserGradeFunction = (root, setGradeForUser) => { - return user => { - return setGradeForUser(user.id, root.querySelector(Selectors.regions.gradingPanel)); + return async user => { + try { + const result = await setGradeForUser(user.id, root.querySelector(Selectors.regions.gradingPanel)); + addToast(await getString('grades:gradesavedfor', 'mod_forum', user)); + + return result; + } catch (error) { + throw error; + } }; }; diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index 29789c6a45e06..8d0a9469386a0 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -727,6 +727,7 @@ $string['gradeforwholeforumhidden'] = 'Grade for forum hidden'; $string['gradeitemnameforwholeforum'] = 'Whole forum grade for {$a->name}'; $string['gradeitemnameforrating'] = 'Rating grade for {$a->name}'; +$string['grades:gradesavedfor'] = 'Grade saved for {$a->fullname}'; // Deprecated since Moodle 3.8. $string['cannotdeletediscussioninsinglediscussion'] = 'You cannot delete the first post in a single discussion';