From cc1a7689cd036d5a70894e6b0ed421e2c3be7adf Mon Sep 17 00:00:00 2001 From: Mathew May Date: Mon, 28 Oct 2019 13:05:32 +0800 Subject: [PATCH] MDL-66074 mod_forum: Grader interface documentation --- .../amd/build/local/grades/grader.min.js.map | 2 +- mod/forum/amd/src/local/grades/grader.js | 37 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/mod/forum/amd/build/local/grades/grader.min.js.map b/mod/forum/amd/build/local/grades/grader.min.js.map index dbfdf9935a1..2e24a1fc698 100644 --- a/mod/forum/amd/build/local/grades/grader.min.js.map +++ b/mod/forum/amd/build/local/grades/grader.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../../src/local/grades/grader.js"],"names":["templateNames","grader","app","gradingPanel","error","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","registerEventListeners","graderLayout","userPicker","saveGradeFunction","graderContainer","getContainer","addEventListener","e","target","closest","buttons","toggleFullscreen","stopImmediatePropagation","preventDefault","closeGrader","close","saveGrade","currentUser","getSaveUserGradeFunction","setGradeForUser","gradingPanelErrors","innerHTML","result","success","addToast","failed","displayGradingError","err","renderForPromise","message","errorString","launch","getListOfUsers","initialUserId","moduleName","fullscreen","showLoader","graderHTML","userList","updateUserContent","rootNode"],"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';\nimport Selectors from './local/grader/selectors';\nimport getUserPicker 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';\nimport {failedUpdate} from 'core_grades/grades/grader/gradingpanel/normalise';\n\nconst templateNames = {\n grader: {\n app: 'mod_forum/local/grades/grader',\n gradingPanel: {\n error: 'mod_forum/local/grades/local/grader/gradingpanel/error',\n },\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, userPicker, saveGradeFunction) => {\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\n return;\n }\n\n if (e.target.closest(Selectors.buttons.closeGrader)) {\n e.stopImmediatePropagation();\n e.preventDefault();\n\n graderLayout.close();\n\n return;\n }\n\n if (e.target.closest(Selectors.buttons.saveGrade)) {\n saveGradeFunction(userPicker.currentUser);\n }\n });\n};\n\n/**\n * Get the function used to save a user grade.\n *\n * @param {Element} root The container for the grader\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 root.querySelector(Selectors.regions.gradingPanelErrors).innerHTML = '';\n const result = await setGradeForUser(user.id, root.querySelector(Selectors.regions.gradingPanel));\n if (result.success) {\n addToast(await getString('grades:gradesavedfor', 'mod_forum', user));\n }\n if (result.failed) {\n displayGradingError(root, user, result.error);\n }\n\n return result;\n } catch (err) {\n displayGradingError(root, user, err);\n\n return failedUpdate(err);\n }\n };\n};\n\n/**\n * Display a grading error, typically from a failed save.\n *\n * @param {Element} root The container for the grader\n * @param {Object} user The user who was errored\n * @param {Object} err The details of the error\n */\nconst displayGradingError = async(root, user, err) => {\n const [\n {html, js},\n errorString\n ] = await Promise.all([\n Templates.renderForPromise(templateNames.grader.gradingPanel.error, {error: err}),\n await getString('grades:gradesavefailed', 'mod_forum', {error: err.message, ...user}),\n ]);\n\n Templates.replaceNodeContents(root.querySelector(Selectors.regions.gradingPanelErrors), html, js);\n addToast(errorString);\n};\n\n/**\n * Launch the grader interface with the specified parameters.\n *\n * @param {Function} getListOfUsers A function to get the list of users\n * @param {Function} getContentForUser A function to get the content for a specific user\n * @param {Function} getGradeForUser A function get the grade details for a specific user\n * @param {Function} setGradeForUser A function to set the grade for a specific user\n */\nexport const launch = async(getListOfUsers, getContentForUser, getGradeForUser, setGradeForUser, {\n initialUserId = null, 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 const saveGradeFunction = getSaveUserGradeFunction(graderContainer, setGradeForUser);\n\n Templates.replaceNodeContents(graderContainer, graderHTML, '');\n const updateUserContent = getUpdateUserContentFunction(graderContainer, getContentForUser, getGradeForUser);\n\n // Fetch the userpicker for display.\n const userPicker = await getUserPicker(\n userList,\n updateUserContent,\n saveGradeFunction,\n {\n initialUserId,\n },\n );\n\n // Register all event listeners.\n registerEventListeners(graderLayout, userPicker, saveGradeFunction);\n\n // Display the newly created user picker.\n displayUserPicker(graderContainer, userPicker.rootNode);\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","gradingPanel","error","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","registerEventListeners","graderLayout","userPicker","saveGradeFunction","graderContainer","getContainer","addEventListener","e","target","closest","buttons","toggleFullscreen","stopImmediatePropagation","preventDefault","closeGrader","close","saveGrade","currentUser","getSaveUserGradeFunction","setGradeForUser","gradingPanelErrors","innerHTML","result","success","addToast","failed","displayGradingError","err","renderForPromise","message","errorString","launch","getListOfUsers","initialUserId","moduleName","fullscreen","showLoader","graderHTML","userList","updateUserContent","rootNode"],"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';\nimport Selectors from './local/grader/selectors';\nimport getUserPicker 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';\nimport {failedUpdate} from 'core_grades/grades/grader/gradingpanel/normalise';\n\nconst templateNames = {\n grader: {\n app: 'mod_forum/local/grades/grader',\n gradingPanel: {\n error: 'mod_forum/local/grades/local/grader/gradingpanel/error',\n },\n },\n};\n\n/**\n * Helper function that replaces the user picker placeholder with what we get back from the user picker class.\n *\n * @param {HTMLElement} root\n * @param {String} html\n */\nconst displayUserPicker = (root, html) => {\n const pickerRegion = root.querySelector(Selectors.regions.pickerRegion);\n Templates.replaceNodeContents(pickerRegion, html, '');\n};\n\n/**\n * To be removed, this is now done as a part of Templates.renderForPromise()\n *\n * @param {String} html\n * @param {String} js\n * @return {[*, *]}\n */\nconst fetchContentFromRender = (html, js) => {\n return [html, js];\n};\n\n/**\n * Here we build the function that is passed to the user picker that'll handle updating the user content area\n * of the grading interface.\n *\n * @param {HTMLElement} root\n * @param {Function} getContentForUser\n * @param {Function} getGradeForUser\n * @return {Function}\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\n/**\n * Add click handlers to the buttons in the header of the grading interface.\n *\n * @param {HTMLElement} graderLayout\n * @param {Object} userPicker\n * @param {Function} saveGradeFunction\n */\nconst registerEventListeners = (graderLayout, userPicker, saveGradeFunction) => {\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\n return;\n }\n\n if (e.target.closest(Selectors.buttons.closeGrader)) {\n e.stopImmediatePropagation();\n e.preventDefault();\n\n graderLayout.close();\n\n return;\n }\n\n if (e.target.closest(Selectors.buttons.saveGrade)) {\n saveGradeFunction(userPicker.currentUser);\n }\n });\n};\n\n/**\n * Get the function used to save a user grade.\n *\n * @param {HTMLElement} root The container for the grader\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 root.querySelector(Selectors.regions.gradingPanelErrors).innerHTML = '';\n const result = await setGradeForUser(user.id, root.querySelector(Selectors.regions.gradingPanel));\n if (result.success) {\n addToast(await getString('grades:gradesavedfor', 'mod_forum', user));\n }\n if (result.failed) {\n displayGradingError(root, user, result.error);\n }\n\n return result;\n } catch (err) {\n displayGradingError(root, user, err);\n\n return failedUpdate(err);\n }\n };\n};\n\n/**\n * Display a grading error, typically from a failed save.\n *\n * @param {HTMLElement} root The container for the grader\n * @param {Object} user The user who was errored\n * @param {Object} err The details of the error\n */\nconst displayGradingError = async(root, user, err) => {\n const [\n {html, js},\n errorString\n ] = await Promise.all([\n Templates.renderForPromise(templateNames.grader.gradingPanel.error, {error: err}),\n await getString('grades:gradesavefailed', 'mod_forum', {error: err.message, ...user}),\n ]);\n\n Templates.replaceNodeContents(root.querySelector(Selectors.regions.gradingPanelErrors), html, js);\n addToast(errorString);\n};\n\n/**\n * Launch the grader interface with the specified parameters.\n *\n * @param {Function} getListOfUsers A function to get the list of users\n * @param {Function} getContentForUser A function to get the content for a specific user\n * @param {Function} getGradeForUser A function get the grade details for a specific user\n * @param {Function} setGradeForUser A function to set the grade for a specific user\n */\nexport const launch = async(getListOfUsers, getContentForUser, getGradeForUser, setGradeForUser, {\n initialUserId = null, moduleName\n} = {}) => {\n\n // We need all of these functions to be executed in series, if one step runs before another the interface\n // will not work.\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 const saveGradeFunction = getSaveUserGradeFunction(graderContainer, setGradeForUser);\n\n Templates.replaceNodeContents(graderContainer, graderHTML, '');\n const updateUserContent = getUpdateUserContentFunction(graderContainer, getContentForUser, getGradeForUser);\n\n // Fetch the userpicker for display.\n const userPicker = await getUserPicker(\n userList,\n updateUserContent,\n saveGradeFunction,\n {\n initialUserId,\n },\n );\n\n // Register all event listeners.\n registerEventListeners(graderLayout, userPicker, saveGradeFunction);\n\n // Display the newly created user picker.\n displayUserPicker(graderContainer, userPicker.rootNode);\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 68301924663..39a9d7a64b2 100644 --- a/mod/forum/amd/src/local/grades/grader.js +++ b/mod/forum/amd/src/local/grades/grader.js @@ -39,15 +39,37 @@ const templateNames = { }, }; +/** + * Helper function that replaces the user picker placeholder with what we get back from the user picker class. + * + * @param {HTMLElement} root + * @param {String} html + */ const displayUserPicker = (root, html) => { const pickerRegion = root.querySelector(Selectors.regions.pickerRegion); Templates.replaceNodeContents(pickerRegion, html, ''); }; +/** + * To be removed, this is now done as a part of Templates.renderForPromise() + * + * @param {String} html + * @param {String} js + * @return {[*, *]} + */ const fetchContentFromRender = (html, js) => { return [html, js]; }; +/** + * Here we build the function that is passed to the user picker that'll handle updating the user content area + * of the grading interface. + * + * @param {HTMLElement} root + * @param {Function} getContentForUser + * @param {Function} getGradeForUser + * @return {Function} + */ const getUpdateUserContentFunction = (root, getContentForUser, getGradeForUser) => { return async(user) => { const [ @@ -67,6 +89,13 @@ const getUpdateUserContentFunction = (root, getContentForUser, getGradeForUser) }; }; +/** + * Add click handlers to the buttons in the header of the grading interface. + * + * @param {HTMLElement} graderLayout + * @param {Object} userPicker + * @param {Function} saveGradeFunction + */ const registerEventListeners = (graderLayout, userPicker, saveGradeFunction) => { const graderContainer = graderLayout.getContainer(); graderContainer.addEventListener('click', (e) => { @@ -96,12 +125,12 @@ const registerEventListeners = (graderLayout, userPicker, saveGradeFunction) => /** * Get the function used to save a user grade. * - * @param {Element} root The container for the grader + * @param {HTMLElement} root The container for the grader * @param {Function} setGradeForUser The function that will be called. * @return {Function} */ const getSaveUserGradeFunction = (root, setGradeForUser) => { - return async user => { + return async(user) => { try { root.querySelector(Selectors.regions.gradingPanelErrors).innerHTML = ''; const result = await setGradeForUser(user.id, root.querySelector(Selectors.regions.gradingPanel)); @@ -124,7 +153,7 @@ const getSaveUserGradeFunction = (root, setGradeForUser) => { /** * Display a grading error, typically from a failed save. * - * @param {Element} root The container for the grader + * @param {HTMLElement} root The container for the grader * @param {Object} user The user who was errored * @param {Object} err The details of the error */ @@ -153,6 +182,8 @@ export const launch = async(getListOfUsers, getContentForUser, getGradeForUser, initialUserId = null, moduleName } = {}) => { + // We need all of these functions to be executed in series, if one step runs before another the interface + // will not work. const [ graderLayout, graderHTML,