From 6794f1293f130b7dffe7f5445e52c4dfc535ec00 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Thu, 10 Aug 2023 15:39:52 +0100 Subject: [PATCH] MDL-74610 quiz: multiple grades - add grade item --- .../amd/build/edit_multiple_grades.min.js | 4 +- .../amd/build/edit_multiple_grades.min.js.map | 2 +- mod/quiz/amd/src/edit_multiple_grades.js | 43 +++++++++++++++++-- mod/quiz/lang/en/quiz.php | 1 + mod/quiz/templates/edit_grading_page.mustache | 3 +- .../behat/editing_multiple_grades.feature | 10 +++++ 6 files changed, 56 insertions(+), 7 deletions(-) diff --git a/mod/quiz/amd/build/edit_multiple_grades.min.js b/mod/quiz/amd/build/edit_multiple_grades.min.js index 2e1634aefeb..ab317554d2c 100644 --- a/mod/quiz/amd/build/edit_multiple_grades.min.js +++ b/mod/quiz/amd/build/edit_multiple_grades.min.js @@ -1,10 +1,10 @@ -define("mod_quiz/edit_multiple_grades",["exports","core/ajax","core/loadingicon","core/notification","core/pending"],(function(_exports,_ajax,_loadingicon,_notification,_pending){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +define("mod_quiz/edit_multiple_grades",["exports","core/ajax","core/loadingicon","core/notification","core/pending","core/str"],(function(_exports,_ajax,_loadingicon,_notification,_pending,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} /** * JavaScript for managing multiple grade items for a quiz. * * @module mod_quiz/edit_multiple_grades * @copyright 2023 THe Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending);const handleGradeItemDelete=e=>{e.preventDefault();const pending=new _pending.default("delete-quiz-grade-item"),tableCell=e.target.closest("td");(0,_loadingicon.addIconToContainerRemoveOnCompletion)(tableCell,pending);const tableRow=tableCell.closest("tr");((quizId,gradeItemId)=>(0,_ajax.call)([{methodname:"mod_quiz_delete_grade_items",args:{quizid:quizId,quizgradeitems:[{id:gradeItemId}]}}])[0])(tableRow.closest("table").dataset.quizId,tableRow.dataset.quizGradeItemId).then((()=>pending.resolve())).then((()=>{window.location.reload()})).catch(_notification.default.exception)},handleGradeItemClick=e=>{const link=e.target.closest("a");link&&link.dataset.actionDelete&&handleGradeItemDelete(e)};_exports.init=()=>{(()=>{const gradeItemTable=document.getElementById("mod_quiz-grade-item-list");gradeItemTable&&gradeItemTable.addEventListener("click",handleGradeItemClick)})()}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending);const handleGradeItemDelete=e=>{e.preventDefault();const pending=new _pending.default("delete-quiz-grade-item"),tableCell=e.target.closest("td");(0,_loadingicon.addIconToContainerRemoveOnCompletion)(tableCell,pending);const tableRow=tableCell.closest("tr");((quizId,gradeItemId)=>(0,_ajax.call)([{methodname:"mod_quiz_delete_grade_items",args:{quizid:quizId,quizgradeitems:[{id:gradeItemId}]}}])[0])(tableRow.closest("table").dataset.quizId,tableRow.dataset.quizGradeItemId).then((()=>pending.resolve())).then((()=>{window.location.reload()})).catch(_notification.default.exception)},handleGradeItemClick=e=>{const link=e.target.closest("a");link&&link.dataset.actionDelete&&handleGradeItemDelete(e)},handleAddGradeItemClick=e=>{e.preventDefault();const pending=new _pending.default("delete-quiz-grade-item");(0,_loadingicon.addIconToContainerRemoveOnCompletion)(e.target.parentNode,pending);const quizId=e.target.dataset.quizId;(0,_str.get_string)("gradeitemdefaultname","quiz").then((name=>((quizId,name)=>(0,_ajax.call)([{methodname:"mod_quiz_create_grade_items",args:{quizid:quizId,quizgradeitems:[{name:name}]}}])[0])(quizId,name))).then((()=>pending.resolve())).then((()=>{window.location.reload()})).catch(_notification.default.exception)};_exports.init=()=>{(()=>{const gradeItemTable=document.getElementById("mod_quiz-grade-item-list");gradeItemTable&&gradeItemTable.addEventListener("click",handleGradeItemClick),document.getElementById("mod_quiz-add_grade_item").addEventListener("click",handleAddGradeItemClick)})()}})); //# sourceMappingURL=edit_multiple_grades.min.js.map \ No newline at end of file diff --git a/mod/quiz/amd/build/edit_multiple_grades.min.js.map b/mod/quiz/amd/build/edit_multiple_grades.min.js.map index 79ba10bc902..826b40f5d57 100644 --- a/mod/quiz/amd/build/edit_multiple_grades.min.js.map +++ b/mod/quiz/amd/build/edit_multiple_grades.min.js.map @@ -1 +1 @@ -{"version":3,"file":"edit_multiple_grades.min.js","sources":["../src/edit_multiple_grades.js"],"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 * JavaScript for managing multiple grade items for a quiz.\n *\n * @module mod_quiz/edit_multiple_grades\n * @copyright 2023 THe Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {call as fetchMany} from 'core/ajax';\nimport {addIconToContainerRemoveOnCompletion} from 'core/loadingicon';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\n\n/**\n * Call the Ajax service to delete a quiz grade item.\n *\n * @param {Number} quizId\n * @param {Number} gradeItemId\n * @return {Promise}\n */\nconst deleteGradeItem = (quizId, gradeItemId) => fetchMany([{\n methodname: 'mod_quiz_delete_grade_items',\n args: {\n quizid: quizId,\n quizgradeitems: [{id: gradeItemId}],\n }\n}])[0];\n\n/**\n * Handle the an event if it is a click on the delete icon.\n *\n * @param {Event} e click event.\n */\nconst handleGradeItemDelete = (e) => {\n e.preventDefault();\n const pending = new Pending('delete-quiz-grade-item');\n\n const tableCell = e.target.closest('td');\n addIconToContainerRemoveOnCompletion(tableCell, pending);\n\n const tableRow = tableCell.closest('tr');\n const quizId = tableRow.closest('table').dataset.quizId;\n const gradeItemId = tableRow.dataset.quizGradeItemId;\n\n deleteGradeItem(quizId, gradeItemId)\n .then(() => pending.resolve())\n .then(() => {\n window.location.reload();\n })\n .catch(Notification.exception);\n};\n\n/**\n * Handle clicks in the table the shows the grade items.\n *\n * @param {Event} e click event.\n */\nconst handleGradeItemClick = (e) => {\n const link = e.target.closest('a');\n\n if (!link) {\n return;\n }\n\n if (link.dataset.actionDelete) {\n handleGradeItemDelete(e);\n }\n};\n\n/**\n * Replace the container with a new version.\n */\nconst registerEventListeners = () => {\n const gradeItemTable = document.getElementById('mod_quiz-grade-item-list');\n if (!gradeItemTable) {\n return;\n }\n\n gradeItemTable.addEventListener('click', handleGradeItemClick);\n};\n\n/**\n * Entry point.\n */\nexport const init = () => {\n registerEventListeners();\n};\n"],"names":["handleGradeItemDelete","e","preventDefault","pending","Pending","tableCell","target","closest","tableRow","quizId","gradeItemId","methodname","args","quizid","quizgradeitems","id","deleteGradeItem","dataset","quizGradeItemId","then","resolve","window","location","reload","catch","Notification","exception","handleGradeItemClick","link","actionDelete","gradeItemTable","document","getElementById","addEventListener","registerEventListeners"],"mappings":";;;;;;;sLAgDMA,sBAAyBC,IAC3BA,EAAEC,uBACIC,QAAU,IAAIC,iBAAQ,0BAEtBC,UAAYJ,EAAEK,OAAOC,QAAQ,4DACEF,UAAWF,eAE1CK,SAAWH,UAAUE,QAAQ,MApBf,EAACE,OAAQC,eAAgB,cAAU,CAAC,CACxDC,WAAY,8BACZC,KAAM,CACFC,OAAQJ,OACRK,eAAgB,CAAC,CAACC,GAAIL,kBAE1B,GAkBAM,CAHeR,SAASD,QAAQ,SAASU,QAAQR,OAC7BD,SAASS,QAAQC,iBAGhCC,MAAK,IAAMhB,QAAQiB,YACnBD,MAAK,KACFE,OAAOC,SAASC,YAEnBC,MAAMC,sBAAaC,YAQtBC,qBAAwB1B,UACpB2B,KAAO3B,EAAEK,OAAOC,QAAQ,KAEzBqB,MAIDA,KAAKX,QAAQY,cACb7B,sBAAsBC,kBAmBV,KAZW,YACrB6B,eAAiBC,SAASC,eAAe,4BAC1CF,gBAILA,eAAeG,iBAAiB,QAASN,uBAOzCO"} \ No newline at end of file +{"version":3,"file":"edit_multiple_grades.min.js","sources":["../src/edit_multiple_grades.js"],"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 * JavaScript for managing multiple grade items for a quiz.\n *\n * @module mod_quiz/edit_multiple_grades\n * @copyright 2023 THe Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {call as fetchMany} from 'core/ajax';\nimport {addIconToContainerRemoveOnCompletion} from 'core/loadingicon';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport {get_string as getString} from 'core/str';\n\n/**\n * Call the Ajax service to add a quiz grade item.\n *\n * @param {Number} quizId\n * @param {String} name\n * @return {Promise}\n */\nconst addGradeItem = (quizId, name) => fetchMany([{\n methodname: 'mod_quiz_create_grade_items',\n args: {\n quizid: quizId,\n quizgradeitems: [{name: name}],\n }\n}])[0];\n\n/**\n * Call the Ajax service to delete a quiz grade item.\n *\n * @param {Number} quizId\n * @param {Number} gradeItemId\n * @return {Promise}\n */\nconst deleteGradeItem = (quizId, gradeItemId) => fetchMany([{\n methodname: 'mod_quiz_delete_grade_items',\n args: {\n quizid: quizId,\n quizgradeitems: [{id: gradeItemId}],\n }\n}])[0];\n\n/**\n * Handle the an event if it is a click on the delete icon.\n *\n * @param {Event} e click event.\n */\nconst handleGradeItemDelete = (e) => {\n e.preventDefault();\n const pending = new Pending('delete-quiz-grade-item');\n\n const tableCell = e.target.closest('td');\n addIconToContainerRemoveOnCompletion(tableCell, pending);\n\n const tableRow = tableCell.closest('tr');\n const quizId = tableRow.closest('table').dataset.quizId;\n const gradeItemId = tableRow.dataset.quizGradeItemId;\n\n deleteGradeItem(quizId, gradeItemId)\n .then(() => pending.resolve())\n .then(() => {\n window.location.reload();\n })\n .catch(Notification.exception);\n};\n\n/**\n * Handle clicks in the table the shows the grade items.\n *\n * @param {Event} e click event.\n */\nconst handleGradeItemClick = (e) => {\n const link = e.target.closest('a');\n\n if (!link) {\n return;\n }\n\n if (link.dataset.actionDelete) {\n handleGradeItemDelete(e);\n }\n};\n\n/**\n * Handle clicks on the 'Add grade item' table.\n *\n * @param {Event} e click event.\n */\nconst handleAddGradeItemClick = (e) => {\n e.preventDefault();\n const pending = new Pending('delete-quiz-grade-item');\n addIconToContainerRemoveOnCompletion(e.target.parentNode, pending);\n\n const quizId = e.target.dataset.quizId;\n\n getString('gradeitemdefaultname', 'quiz')\n .then((name) => addGradeItem(quizId, name))\n .then(() => pending.resolve())\n .then(() => {\n window.location.reload();\n })\n .catch(Notification.exception);\n};\n\n/**\n * Replace the container with a new version.\n */\nconst registerEventListeners = () => {\n const gradeItemTable = document.getElementById('mod_quiz-grade-item-list');\n if (gradeItemTable) {\n gradeItemTable.addEventListener('click', handleGradeItemClick);\n }\n\n document.getElementById('mod_quiz-add_grade_item').addEventListener('click', handleAddGradeItemClick);\n};\n\n/**\n * Entry point.\n */\nexport const init = () => {\n registerEventListeners();\n};\n"],"names":["handleGradeItemDelete","e","preventDefault","pending","Pending","tableCell","target","closest","tableRow","quizId","gradeItemId","methodname","args","quizid","quizgradeitems","id","deleteGradeItem","dataset","quizGradeItemId","then","resolve","window","location","reload","catch","Notification","exception","handleGradeItemClick","link","actionDelete","handleAddGradeItemClick","parentNode","name","addGradeItem","gradeItemTable","document","getElementById","addEventListener","registerEventListeners"],"mappings":";;;;;;;sLAgEMA,sBAAyBC,IAC3BA,EAAEC,uBACIC,QAAU,IAAIC,iBAAQ,0BAEtBC,UAAYJ,EAAEK,OAAOC,QAAQ,4DACEF,UAAWF,eAE1CK,SAAWH,UAAUE,QAAQ,MApBf,EAACE,OAAQC,eAAgB,cAAU,CAAC,CACxDC,WAAY,8BACZC,KAAM,CACFC,OAAQJ,OACRK,eAAgB,CAAC,CAACC,GAAIL,kBAE1B,GAkBAM,CAHeR,SAASD,QAAQ,SAASU,QAAQR,OAC7BD,SAASS,QAAQC,iBAGhCC,MAAK,IAAMhB,QAAQiB,YACnBD,MAAK,KACFE,OAAOC,SAASC,YAEnBC,MAAMC,sBAAaC,YAQtBC,qBAAwB1B,UACpB2B,KAAO3B,EAAEK,OAAOC,QAAQ,KAEzBqB,MAIDA,KAAKX,QAAQY,cACb7B,sBAAsBC,IASxB6B,wBAA2B7B,IAC7BA,EAAEC,uBACIC,QAAU,IAAIC,iBAAQ,gFACSH,EAAEK,OAAOyB,WAAY5B,eAEpDM,OAASR,EAAEK,OAAOW,QAAQR,2BAEtB,uBAAwB,QAC7BU,MAAMa,MA7EM,EAACvB,OAAQuB,QAAS,cAAU,CAAC,CAC9CrB,WAAY,8BACZC,KAAM,CACFC,OAAQJ,OACRK,eAAgB,CAAC,CAACkB,KAAMA,WAE5B,GAuEoBC,CAAaxB,OAAQuB,QACpCb,MAAK,IAAMhB,QAAQiB,YACnBD,MAAK,KACFE,OAAOC,SAASC,YAEnBC,MAAMC,sBAAaC,0BAkBR,KAZW,YACrBQ,eAAiBC,SAASC,eAAe,4BAC3CF,gBACAA,eAAeG,iBAAiB,QAASV,sBAG7CQ,SAASC,eAAe,2BAA2BC,iBAAiB,QAASP,0BAO7EQ"} \ No newline at end of file diff --git a/mod/quiz/amd/src/edit_multiple_grades.js b/mod/quiz/amd/src/edit_multiple_grades.js index 38412c0873c..6d1898201ca 100644 --- a/mod/quiz/amd/src/edit_multiple_grades.js +++ b/mod/quiz/amd/src/edit_multiple_grades.js @@ -25,6 +25,22 @@ import {call as fetchMany} from 'core/ajax'; import {addIconToContainerRemoveOnCompletion} from 'core/loadingicon'; import Notification from 'core/notification'; import Pending from 'core/pending'; +import {get_string as getString} from 'core/str'; + +/** + * Call the Ajax service to add a quiz grade item. + * + * @param {Number} quizId + * @param {String} name + * @return {Promise} + */ +const addGradeItem = (quizId, name) => fetchMany([{ + methodname: 'mod_quiz_create_grade_items', + args: { + quizid: quizId, + quizgradeitems: [{name: name}], + } +}])[0]; /** * Call the Ajax service to delete a quiz grade item. @@ -82,16 +98,37 @@ const handleGradeItemClick = (e) => { } }; +/** + * Handle clicks on the 'Add grade item' table. + * + * @param {Event} e click event. + */ +const handleAddGradeItemClick = (e) => { + e.preventDefault(); + const pending = new Pending('delete-quiz-grade-item'); + addIconToContainerRemoveOnCompletion(e.target.parentNode, pending); + + const quizId = e.target.dataset.quizId; + + getString('gradeitemdefaultname', 'quiz') + .then((name) => addGradeItem(quizId, name)) + .then(() => pending.resolve()) + .then(() => { + window.location.reload(); + }) + .catch(Notification.exception); +}; + /** * Replace the container with a new version. */ const registerEventListeners = () => { const gradeItemTable = document.getElementById('mod_quiz-grade-item-list'); - if (!gradeItemTable) { - return; + if (gradeItemTable) { + gradeItemTable.addEventListener('click', handleGradeItemClick); } - gradeItemTable.addEventListener('click', handleGradeItemClick); + document.getElementById('mod_quiz-add_grade_item').addEventListener('click', handleAddGradeItemClick); }; /** diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php index 6fb7ec30551..0786d0addfd 100644 --- a/mod/quiz/lang/en/quiz.php +++ b/mod/quiz/lang/en/quiz.php @@ -440,6 +440,7 @@ $string['gradeaverage'] = 'Average grade'; $string['gradeboundary'] = 'Grade boundary'; $string['gradeessays'] = 'Grade essays'; $string['gradehighest'] = 'Highest grade'; +$string['gradeitemdefaultname'] = 'New grade item'; $string['gradeitemdelete'] = 'Delete grade item {$a}'; $string['gradeitemnewname'] = 'New name for grade item {$a}'; $string['gradeitems'] = 'Grade items'; diff --git a/mod/quiz/templates/edit_grading_page.mustache b/mod/quiz/templates/edit_grading_page.mustache index fa762ffb6ac..b017a73392f 100644 --- a/mod/quiz/templates/edit_grading_page.mustache +++ b/mod/quiz/templates/edit_grading_page.mustache @@ -92,7 +92,8 @@ {{/hasgradeitems}}
- +

Mark scheme

diff --git a/mod/quiz/tests/behat/editing_multiple_grades.feature b/mod/quiz/tests/behat/editing_multiple_grades.feature index ca7e9fb9564..a04e59e2ecd 100644 --- a/mod/quiz/tests/behat/editing_multiple_grades.feature +++ b/mod/quiz/tests/behat/editing_multiple_grades.feature @@ -43,6 +43,16 @@ Feature: Setup multiple grades for a quiz And "Delete" "icon" should not exist in the "Intelligence" "table_row" And "Delete" "icon" should exist in the "Unused grade item" "table_row" + @javascript + Scenario: A grade item can be created + Given quiz "Quiz 1" contains the following questions: + | question | page | + | Question A | 1 | + When I am on the "Quiz 1" "mod_quiz > multiple grades setup" page logged in as teacher + And I should see "This quiz does not yet have any grade items defined" + And I press "Add grade item" + Then "New grade item" "table_row" should exist + @javascript Scenario: Unused grade items can be deleted Given the following "mod_quiz > grade items" exist: