From a08282a87210ebd435a24d759329fd4370d5098a Mon Sep 17 00:00:00 2001 From: Ilya Tregubov Date: Thu, 3 Nov 2022 10:27:34 +0300 Subject: [PATCH] MDL-75455 gradereport_singleview: PR review fixes. Part of: MDL-75423 --- .../activity_completion_criteria.feature | 2 +- grade/lib.php | 3 +- .../singleview/amd/build/bulkactions.min.js | 4 +- .../amd/build/bulkactions.min.js.map | 2 +- .../singleview/amd/build/selectors.min.js | 3 + .../singleview/amd/build/selectors.min.js.map | 1 + .../report/singleview/amd/src/bulkactions.js | 140 ++++++++++-------- grade/report/singleview/amd/src/selectors.js | 54 +++++++ .../classes/local/ui/bulk_insert.php | 1 - .../singleview/classes/output/action_bar.php | 8 +- .../singleview/classes/report/singleview.php | 2 +- .../lang/en/gradereport_singleview.php | 7 +- grade/report/singleview/styles.css | 9 +- .../singleview/templates/action_bar.mustache | 53 +++++++ .../singleview/templates/bulkinsert.mustache | 37 +++-- .../templates/grade_item_selector.mustache | 2 +- .../templates/page_toggler.mustache | 8 +- .../tests/behat/bulk_insert_grades.feature | 96 ++++++------ .../tests/behat/gradeitemsearch.feature | 2 +- .../tests/behat/reportswitching.feature | 2 +- .../singleview/tests/behat/singleview.feature | 14 +- .../singleview/tests/behat/usersearch.feature | 2 +- 22 files changed, 291 insertions(+), 161 deletions(-) create mode 100644 grade/report/singleview/amd/build/selectors.min.js create mode 100644 grade/report/singleview/amd/build/selectors.min.js.map create mode 100644 grade/report/singleview/amd/src/selectors.js diff --git a/completion/tests/behat/activity_completion_criteria.feature b/completion/tests/behat/activity_completion_criteria.feature index da97899c283..34d114649ab 100644 --- a/completion/tests/behat/activity_completion_criteria.feature +++ b/completion/tests/behat/activity_completion_criteria.feature @@ -134,7 +134,7 @@ Feature: Allow to mark course as completed without cron for activity completion Given I log in as "teacher1" And I am on "Completion course" course homepage And I navigate to "View > Single view" in the course gradebook - And I click on "User" "link" in the ".singleindex" "css_element" + And I click on "Users" "link" in the ".page-toggler" "css_element" And I turn editing mode on And I click on "Student First" in the "user" search widget And I set the field "Override for Test assignment name" to "1" diff --git a/grade/lib.php b/grade/lib.php index 4ec636eae57..2d337b7ecea 100644 --- a/grade/lib.php +++ b/grade/lib.php @@ -1730,7 +1730,8 @@ class grade_structure { if ($menuitems) { $menu = new action_menu($menuitems); $icon = $OUTPUT->pix_icon('i/dropdown', get_string('actions')); - $menu->set_menu_trigger($icon, 'btn btn-icon icon-size-2 bg-secondary d-flex align-items-center justify-content-center'); + $extraclasses = 'btn btn-icon icon-size-2 bg-secondary d-flex align-items-center justify-content-center'; + $menu->set_menu_trigger($icon, $extraclasses); $menu->set_menu_left(); return $OUTPUT->render($menu); diff --git a/grade/report/singleview/amd/build/bulkactions.min.js b/grade/report/singleview/amd/build/bulkactions.min.js index b7fe60c98da..572764203a8 100644 --- a/grade/report/singleview/amd/build/bulkactions.min.js +++ b/grade/report/singleview/amd/build/bulkactions.min.js @@ -1,10 +1,10 @@ -define("gradereport_singleview/bulkactions",["exports","core/pending","core/custom_interaction_events","core/modal_factory","core/templates","core/modal_events"],(function(_exports,_pending,_custom_interaction_events,_modal_factory,_templates,_modal_events){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +define("gradereport_singleview/bulkactions",["exports","core/pending","core/custom_interaction_events","core/modal_factory","core/templates","core/modal_events","core/str","core/notification","gradereport_singleview/selectors"],(function(_exports,_pending,_custom_interaction_events,_modal_factory,_templates,_modal_events,Str,_notification,_selectors){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} /** * Javascript module for bulk actions. * * @module gradereport_singleview/bulkactions * @copyright 2022 Ilya Tregubov * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_pending=_interopRequireDefault(_pending),_custom_interaction_events=_interopRequireDefault(_custom_interaction_events),_modal_factory=_interopRequireDefault(_modal_factory),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events);_exports.init=()=>{const pendingPromise=new _pending.default;registerListenerEvents(),pendingPromise.resolve()};const registerListenerEvents=()=>{const events=["click",_custom_interaction_events.default.events.activate,_custom_interaction_events.default.events.keyboardActivate];_custom_interaction_events.default.define(document,events),events.forEach((event=>{document.addEventListener(event,(async e=>{const trigger=e.target.closest("[data-role]");if(trigger)if("overrideallgrades"===trigger.dataset.role||"overridenonegrades"===trigger.dataset.role){const overrideAll=document.querySelectorAll("input[type=checkbox][name^=override]");if("overridenonegrades"===trigger.dataset.role){const confirm=new M.core.confirm({title:M.util.get_string("removeoverride","gradereport_singleview"),question:M.util.get_string("overridenoneconfirm","gradereport_singleview"),noLabel:M.util.get_string("cancel","moodle"),yesLabel:M.util.get_string("removeoverridesave","gradereport_singleview")});confirm.on("complete-yes",(function(){confirm.hide(),confirm.destroy(),overrideAll.forEach((function(el){el.checked&&el.click()}))}),self),confirm.show()}else overrideAll.forEach((function(el){el.checked||el.click()}))}else if("excludeallgrades"===trigger.dataset.role||"excludenonegrades"===trigger.dataset.role){const excludeAll=document.querySelectorAll("input[type=checkbox][name^=exclude]"),checked="excludeallgrades"===trigger.dataset.role;excludeAll.forEach((function(el){el.checked=checked}))}else"bulklegend"===trigger.dataset.role&&_modal_factory.default.create({type:_modal_factory.default.types.SAVE_CANCEL,body:_templates.default.render("gradereport_singleview/bulkinsert",{id:"bulkinsertmodal",name:"bulkinsertmodal"}),title:"Bulk insert"}).then((function(modal){return modal.setSaveButtonText("Save"),modal.getFooter().find('[data-action="save"]').attr("disabled",!0),modal.getRoot().on(_modal_events.default.hidden,(function(){modal.getRoot().remove()})),modal.getRoot().on("change",'input[type="checkbox"]',(e=>{if(e.preventDefault(),e.target.checked){modal.getRoot().find(".formdata").removeClass("dimmed_text"),modal.getRoot().find('input[type="radio"]').removeAttr("disabled"),modal.getRoot().find('input[type="text"]').removeAttr("disabled");modal.getRoot().find('input[type="radio"]:checked').val()&&modal.getFooter().find('[data-action="save"]').removeAttr("disabled")}else modal.getRoot().find(".formdata").addClass("dimmed_text"),modal.getRoot().find('input[type="radio"]').attr("disabled",!0),modal.getRoot().find('input[type="text"]').attr("disabled",!0),modal.getFooter().find('[data-action="save"]').attr("disabled",!0)})),modal.getRoot().on("change",'input[type="radio"]',(e=>{e.preventDefault(),modal.getFooter().find('[data-action="save"]').removeAttr("disabled")})),modal.getRoot().on(_modal_events.default.save,(function(){document.querySelector('input[type="checkbox"][name^=bulk]').checked=!0;const formRadioData=modal.getRoot().find('input[type="radio"]:checked').val();document.querySelector("select[name^=bulk]").value=formRadioData;const formData=modal.getRoot().find(".form-control").val();document.querySelector('input[type="text"][name^=bulk]').value=formData,document.querySelector('input[type="submit"]').click()})),modal.show(),modal}))}))}))}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_pending=_interopRequireDefault(_pending),_custom_interaction_events=_interopRequireDefault(_custom_interaction_events),_modal_factory=_interopRequireDefault(_modal_factory),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),Str=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Str),_notification=_interopRequireDefault(_notification),_selectors=_interopRequireDefault(_selectors);_exports.init=()=>{const pendingPromise=new _pending.default;registerListenerEvents(),pendingPromise.resolve()};const registerListenerEvents=()=>{const events=["click",_custom_interaction_events.default.events.activate,_custom_interaction_events.default.events.keyboardActivate];_custom_interaction_events.default.define(document,events),events.forEach((event=>{document.addEventListener(event,(async e=>{const trigger=e.target.closest(_selectors.default.actions.bulkaction);if(trigger)if("overrideallgrades"===trigger.dataset.action||"overridenonegrades"===trigger.dataset.action){const override=document.querySelectorAll(_selectors.default.elements.override);"overridenonegrades"===trigger.dataset.action?Str.get_strings([{key:"removeoverride",component:"gradereport_singleview"},{key:"overridenoneconfirm",component:"gradereport_singleview"},{key:"removeoverridesave",component:"gradereport_singleview"},{key:"cancel",component:"moodle"}]).done((strings=>{_notification.default.confirm(strings[0],strings[1],strings[2],strings[3],(()=>{override.forEach((el=>{el.checked&&el.click()}))}))})).fail(_notification.default.exception):override.forEach((el=>{el.checked||el.click()}))}else if("excludeallgrades"===trigger.dataset.action||"excludenonegrades"===trigger.dataset.action){const exclude=document.querySelectorAll(_selectors.default.elements.exclude),checked="excludeallgrades"===trigger.dataset.action;exclude.forEach((el=>{el.checked=checked}))}else"bulklegend"===trigger.dataset.action&&Str.get_strings([{key:"bulklegend",component:"gradereport_singleview"},{key:"save",component:"moodle"}]).done((strings=>{_modal_factory.default.create({type:_modal_factory.default.types.SAVE_CANCEL,body:_templates.default.render("gradereport_singleview/bulkinsert",{id:"bulkinsertmodal",name:"bulkinsertmodal"}),title:strings[0]}).then((modal=>(modal.setSaveButtonText(strings[1]),modal.getFooter().find(_selectors.default.elements.modalsave).attr("disabled",!0),modal.getRoot().on(_modal_events.default.hidden,(()=>{modal.getRoot().remove()})),modal.getRoot().on("change",_selectors.default.elements.warningcheckbox,(e=>{if(e.preventDefault(),e.target.checked){modal.getRoot().find(_selectors.default.elements.modalformdata).removeClass("dimmed_text"),modal.getRoot().find(_selectors.default.elements.modalradio).removeAttr("disabled"),modal.getRoot().find(_selectors.default.elements.modalinput).removeAttr("disabled");modal.getRoot().find(_selectors.default.elements.modalradiochecked).val()&&modal.getFooter().find(_selectors.default.elements.modalsave).removeAttr("disabled")}else modal.getRoot().find(_selectors.default.elements.modalformdata).addClass("dimmed_text"),modal.getRoot().find(_selectors.default.elements.modalradio).attr("disabled",!0),modal.getRoot().find(_selectors.default.elements.modalinput).attr("disabled",!0),modal.getFooter().find(_selectors.default.elements.modalsave).attr("disabled",!0)})),modal.getRoot().on("change",_selectors.default.elements.modalradio,(e=>{e.preventDefault(),modal.getFooter().find(_selectors.default.elements.modalsave).removeAttr("disabled")})),modal.getRoot().on(_modal_events.default.save,(()=>{document.querySelector(_selectors.default.elements.enablebulkinsert).checked=!0;const formRadioData=modal.getRoot().find(_selectors.default.elements.modalradiochecked).val();document.querySelector(_selectors.default.elements.formradio).value=formRadioData;const formData=modal.getRoot().find(_selectors.default.elements.modalgrade).val();document.querySelector(_selectors.default.elements.formgrade).value=formData,document.querySelector(_selectors.default.elements.formsave).click()})),modal.show(),modal))).fail(_notification.default.exception)})).fail(_notification.default.exception)}))}))}})); //# sourceMappingURL=bulkactions.min.js.map \ No newline at end of file diff --git a/grade/report/singleview/amd/build/bulkactions.min.js.map b/grade/report/singleview/amd/build/bulkactions.min.js.map index f06d42d1cad..7eb8f160d80 100644 --- a/grade/report/singleview/amd/build/bulkactions.min.js.map +++ b/grade/report/singleview/amd/build/bulkactions.min.js.map @@ -1 +1 @@ -{"version":3,"file":"bulkactions.min.js","sources":["../src/bulkactions.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 module for bulk actions.\n *\n * @module gradereport_singleview/bulkactions\n * @copyright 2022 Ilya Tregubov \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Pending from 'core/pending';\nimport CustomEvents from \"core/custom_interaction_events\";\nimport ModalFactory from 'core/modal_factory';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\n\n/**\n * Initialize module.\n */\nexport const init = () => {\n const pendingPromise = new Pending();\n registerListenerEvents();\n pendingPromise.resolve();\n};\n\n/**\n * Register bulk actions related event listeners.\n *\n * @method registerListenerEvents\n */\nconst registerListenerEvents = () => {\n const events = [\n 'click',\n CustomEvents.events.activate,\n CustomEvents.events.keyboardActivate\n ];\n CustomEvents.define(document, events);\n\n // Register events.\n events.forEach((event) => {\n document.addEventListener(event, async(e) => {\n const trigger = e.target.closest('[data-role]');\n if (trigger) {\n if ((trigger.dataset.role === 'overrideallgrades') || (trigger.dataset.role === 'overridenonegrades')) {\n const overrideAll = document.querySelectorAll('input[type=checkbox][name^=override]');\n\n if (trigger.dataset.role === 'overridenonegrades') {\n const confirm = new M.core.confirm({\n title: M.util.get_string('removeoverride', 'gradereport_singleview'),\n question: M.util.get_string('overridenoneconfirm', 'gradereport_singleview'),\n noLabel: M.util.get_string('cancel', 'moodle'),\n yesLabel: M.util.get_string('removeoverridesave', 'gradereport_singleview')\n });\n\n confirm.on('complete-yes', function () {\n confirm.hide();\n confirm.destroy();\n\n overrideAll.forEach(function (el) {\n if (el.checked) {\n el.click();\n }\n });\n }, self);\n confirm.show();\n } else {\n overrideAll.forEach(function (el) {\n if (!el.checked) {\n el.click();\n }\n });\n }\n } else if ((trigger.dataset.role === 'excludeallgrades') || (trigger.dataset.role === 'excludenonegrades')) {\n const excludeAll = document.querySelectorAll('input[type=checkbox][name^=exclude]');\n const checked = (trigger.dataset.role === 'excludeallgrades');\n excludeAll.forEach(function (el) {\n el.checked = checked;\n });\n } else if (trigger.dataset.role === 'bulklegend') {\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n body: Templates.render('gradereport_singleview/bulkinsert', {\n id: 'bulkinsertmodal',\n name: 'bulkinsertmodal'\n }),\n title: 'Bulk insert',\n })\n .then(function (modal) {\n modal.setSaveButtonText('Save');\n modal.getFooter().find('[data-action=\"save\"]').attr('disabled', true);\n\n modal.getRoot().on(ModalEvents.hidden, function () {\n modal.getRoot().remove();\n });\n\n modal.getRoot().on('change', 'input[type=\"checkbox\"]',\n (e) => {\n e.preventDefault();\n if (e.target.checked) {\n modal.getRoot().find('.formdata').removeClass('dimmed_text');\n modal.getRoot().find('input[type=\"radio\"]').removeAttr('disabled');\n modal.getRoot().find('input[type=\"text\"]').removeAttr('disabled');\n\n const formRadioData = modal.getRoot().find('input[type=\"radio\"]:checked').val();\n if (formRadioData) {\n modal.getFooter().find('[data-action=\"save\"]').removeAttr('disabled');\n }\n } else {\n modal.getRoot().find('.formdata').addClass('dimmed_text');\n modal.getRoot().find('input[type=\"radio\"]').attr('disabled', true);\n modal.getRoot().find('input[type=\"text\"]').attr('disabled', true);\n modal.getFooter().find('[data-action=\"save\"]').attr('disabled', true);\n }\n });\n\n modal.getRoot().on('change', 'input[type=\"radio\"]',\n (e) => {\n e.preventDefault();\n modal.getFooter().find('[data-action=\"save\"]').removeAttr('disabled');\n });\n\n modal.getRoot().on(ModalEvents.save, function () {\n document.querySelector('input[type=\"checkbox\"][name^=bulk]').checked = true;\n\n const formRadioData = modal.getRoot().find('input[type=\"radio\"]:checked').val();\n const $select = document.querySelector('select[name^=bulk]');\n $select.value = formRadioData;\n\n const formData = modal.getRoot().find('.form-control').val();\n document.querySelector('input[type=\"text\"][name^=bulk]').value = formData;\n document.querySelector('input[type=\"submit\"]').click();\n });\n\n modal.show();\n\n return modal;\n });\n }\n }\n });\n });\n};\n"],"names":["pendingPromise","Pending","registerListenerEvents","resolve","events","CustomEvents","activate","keyboardActivate","define","document","forEach","event","addEventListener","async","trigger","e","target","closest","dataset","role","overrideAll","querySelectorAll","confirm","M","core","title","util","get_string","question","noLabel","yesLabel","on","hide","destroy","el","checked","click","self","show","excludeAll","create","type","ModalFactory","types","SAVE_CANCEL","body","Templates","render","id","name","then","modal","setSaveButtonText","getFooter","find","attr","getRoot","ModalEvents","hidden","remove","preventDefault","removeClass","removeAttr","val","addClass","save","querySelector","formRadioData","value","formData"],"mappings":";;;;;;;gXAgCoB,WACVA,eAAiB,IAAIC,iBAC3BC,yBACAF,eAAeG,iBAQbD,uBAAyB,WACrBE,OAAS,CACX,QACAC,mCAAaD,OAAOE,SACpBD,mCAAaD,OAAOG,qDAEXC,OAAOC,SAAUL,QAG9BA,OAAOM,SAASC,QACZF,SAASG,iBAAiBD,OAAOE,MAAAA,UACvBC,QAAUC,EAAEC,OAAOC,QAAQ,kBAC7BH,WAC8B,sBAAzBA,QAAQI,QAAQC,MAA2D,uBAAzBL,QAAQI,QAAQC,KAAgC,OAC7FC,YAAcX,SAASY,iBAAiB,2CAEjB,uBAAzBP,QAAQI,QAAQC,KAA+B,OACzCG,QAAU,IAAIC,EAAEC,KAAKF,QAAQ,CAC/BG,MAAOF,EAAEG,KAAKC,WAAW,iBAAkB,0BAC3CC,SAAUL,EAAEG,KAAKC,WAAW,sBAAuB,0BACnDE,QAASN,EAAEG,KAAKC,WAAW,SAAU,UACrCG,SAAUP,EAAEG,KAAKC,WAAW,qBAAsB,4BAGtDL,QAAQS,GAAG,gBAAgB,WACvBT,QAAQU,OACRV,QAAQW,UAERb,YAAYV,SAAQ,SAAUwB,IACtBA,GAAGC,SACHD,GAAGE,aAGZC,MACHf,QAAQgB,YAERlB,YAAYV,SAAQ,SAAUwB,IACrBA,GAAGC,SACJD,GAAGE,gBAIZ,GAA8B,qBAAzBtB,QAAQI,QAAQC,MAA0D,sBAAzBL,QAAQI,QAAQC,KAA+B,OAClGoB,WAAa9B,SAASY,iBAAiB,uCACvCc,QAAoC,qBAAzBrB,QAAQI,QAAQC,KACjCoB,WAAW7B,SAAQ,SAAUwB,IACzBA,GAAGC,QAAUA,eAEe,eAAzBrB,QAAQI,QAAQC,6BACVqB,OAAO,CAChBC,KAAMC,uBAAaC,MAAMC,YACzBC,KAAMC,mBAAUC,OAAO,oCAAqC,CACxDC,GAAI,kBACJC,KAAM,oBAEVxB,MAAO,gBAENyB,MAAK,SAAUC,cACZA,MAAMC,kBAAkB,QACxBD,MAAME,YAAYC,KAAK,wBAAwBC,KAAK,YAAY,GAEhEJ,MAAMK,UAAUzB,GAAG0B,sBAAYC,QAAQ,WACnCP,MAAMK,UAAUG,YAGpBR,MAAMK,UAAUzB,GAAG,SAAU,0BACxBhB,OACGA,EAAE6C,iBACE7C,EAAEC,OAAOmB,QAAS,CAClBgB,MAAMK,UAAUF,KAAK,aAAaO,YAAY,eAC9CV,MAAMK,UAAUF,KAAK,uBAAuBQ,WAAW,YACvDX,MAAMK,UAAUF,KAAK,sBAAsBQ,WAAW,YAEhCX,MAAMK,UAAUF,KAAK,+BAA+BS,OAEtEZ,MAAME,YAAYC,KAAK,wBAAwBQ,WAAW,iBAG9DX,MAAMK,UAAUF,KAAK,aAAaU,SAAS,eAC3Cb,MAAMK,UAAUF,KAAK,uBAAuBC,KAAK,YAAY,GAC7DJ,MAAMK,UAAUF,KAAK,sBAAsBC,KAAK,YAAY,GAC5DJ,MAAME,YAAYC,KAAK,wBAAwBC,KAAK,YAAY,MAI5EJ,MAAMK,UAAUzB,GAAG,SAAU,uBACxBhB,IACGA,EAAE6C,iBACFT,MAAME,YAAYC,KAAK,wBAAwBQ,WAAW,eAGlEX,MAAMK,UAAUzB,GAAG0B,sBAAYQ,MAAM,WACjCxD,SAASyD,cAAc,sCAAsC/B,SAAU,QAEjEgC,cAAgBhB,MAAMK,UAAUF,KAAK,+BAA+BS,MAC1DtD,SAASyD,cAAc,sBAC/BE,MAAQD,oBAEVE,SAAWlB,MAAMK,UAAUF,KAAK,iBAAiBS,MACvDtD,SAASyD,cAAc,kCAAkCE,MAAQC,SACjE5D,SAASyD,cAAc,wBAAwB9B,WAGnDe,MAAMb,OAECa"} \ No newline at end of file +{"version":3,"file":"bulkactions.min.js","sources":["../src/bulkactions.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 module for bulk actions.\n *\n * @module gradereport_singleview/bulkactions\n * @copyright 2022 Ilya Tregubov \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Pending from 'core/pending';\nimport CustomEvents from \"core/custom_interaction_events\";\nimport ModalFactory from 'core/modal_factory';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\nimport * as Str from 'core/str';\nimport Notification from 'core/notification';\nimport selectors from 'gradereport_singleview/selectors';\n\n/**\n * Initialize module.\n */\nexport const init = () => {\n const pendingPromise = new Pending();\n registerListenerEvents();\n pendingPromise.resolve();\n};\n\n/**\n * Register bulk actions related event listeners.\n *\n * @method registerListenerEvents\n */\nconst registerListenerEvents = () => {\n const events = [\n 'click',\n CustomEvents.events.activate,\n CustomEvents.events.keyboardActivate\n ];\n CustomEvents.define(document, events);\n\n // Register events.\n events.forEach((event) => {\n document.addEventListener(event, async(e) => {\n const trigger = e.target.closest(selectors.actions.bulkaction);\n\n if (trigger) {\n if ((trigger.dataset.action === 'overrideallgrades') || (trigger.dataset.action === 'overridenonegrades')) {\n const override = document.querySelectorAll(selectors.elements.override);\n\n if (trigger.dataset.action === 'overridenonegrades') {\n // Alert for removing all grade overrides on page.\n Str.get_strings([\n {key: 'removeoverride', component: 'gradereport_singleview'},\n {key: 'overridenoneconfirm', component: 'gradereport_singleview'},\n {key: 'removeoverridesave', component: 'gradereport_singleview'},\n {key: 'cancel', component: 'moodle'},\n ]).done((strings) => {\n Notification.confirm(\n strings[0],\n strings[1],\n strings[2],\n strings[3],\n () => {\n // Uncheck each override checkbox - this will make grade and feedback input fields disabled.\n override.forEach((el) => {\n if (el.checked) {\n el.click();\n }\n });\n });\n }).fail(Notification.exception);\n\n } else {\n // Check each override checkbox - this will make grade and feedback input fields enabled.\n override.forEach((el) => {\n if (!el.checked) {\n el.click();\n }\n });\n }\n } else if ((trigger.dataset.action === 'excludeallgrades') || (trigger.dataset.action === 'excludenonegrades')) {\n const exclude = document.querySelectorAll(selectors.elements.exclude);\n const checked = (trigger.dataset.action === 'excludeallgrades');\n // Uncheck or check each exclude checkbox.\n exclude.forEach((el) => {\n el.checked = checked;\n });\n } else if (trigger.dataset.action === 'bulklegend') {\n // Modal for bulk insert grades.\n Str.get_strings([\n {key: 'bulklegend', component: 'gradereport_singleview'},\n {key: 'save', component: 'moodle'},\n ]).done((strings) => {\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n body: Templates.render('gradereport_singleview/bulkinsert', {\n id: 'bulkinsertmodal',\n name: 'bulkinsertmodal'\n }),\n title: strings[0],\n }).then((modal) => {\n modal.setSaveButtonText(strings[1]);\n modal.getFooter().find(selectors.elements.modalsave).attr('disabled', true);\n\n modal.getRoot().on(ModalEvents.hidden, () => {\n modal.getRoot().remove();\n });\n\n // We need to acknowledge that we understand risks of loosing data.\n // Only when acknowledge checkbox is checked we allow selecting insert options.\n modal.getRoot().on('change', selectors.elements.warningcheckbox,\n (e) => {\n e.preventDefault();\n if (e.target.checked) {\n modal.getRoot().find(selectors.elements.modalformdata).removeClass('dimmed_text');\n modal.getRoot().find(selectors.elements.modalradio).removeAttr('disabled');\n modal.getRoot().find(selectors.elements.modalinput).removeAttr('disabled');\n\n const formRadioData = modal.getRoot().find(selectors.elements.modalradiochecked).val();\n // We allow saving grades only when all needed data present on form.\n if (formRadioData) {\n modal.getFooter().find(selectors.elements.modalsave).removeAttr('disabled');\n }\n } else {\n modal.getRoot().find(selectors.elements.modalformdata).addClass('dimmed_text');\n modal.getRoot().find(selectors.elements.modalradio).attr('disabled', true);\n modal.getRoot().find(selectors.elements.modalinput).attr('disabled', true);\n modal.getFooter().find(selectors.elements.modalsave).attr('disabled', true);\n }\n });\n\n // We allow saving grades only when all needed data present on form.\n modal.getRoot().on('change', selectors.elements.modalradio,\n (e) => {\n e.preventDefault();\n modal.getFooter().find(selectors.elements.modalsave).removeAttr('disabled');\n });\n\n modal.getRoot().on(ModalEvents.save, () => {\n // When save button is clicked in modal form we insert data from modal\n // into preexisted hidden bulk insert form and Save button for table form.\n document.querySelector(selectors.elements.enablebulkinsert).checked = true;\n const formRadioData = modal.getRoot().find(selectors.elements.modalradiochecked).val();\n const $select = document.querySelector(selectors.elements.formradio);\n $select.value = formRadioData;\n\n const formData = modal.getRoot().find(selectors.elements.modalgrade).val();\n document.querySelector(selectors.elements.formgrade).value = formData;\n document.querySelector(selectors.elements.formsave).click();\n });\n\n modal.show();\n\n return modal;\n }).fail(Notification.exception);\n }).fail(Notification.exception);\n }\n }\n });\n });\n};\n"],"names":["pendingPromise","Pending","registerListenerEvents","resolve","events","CustomEvents","activate","keyboardActivate","define","document","forEach","event","addEventListener","async","trigger","e","target","closest","selectors","actions","bulkaction","dataset","action","override","querySelectorAll","elements","Str","get_strings","key","component","done","strings","confirm","el","checked","click","fail","Notification","exception","exclude","create","type","ModalFactory","types","SAVE_CANCEL","body","Templates","render","id","name","title","then","modal","setSaveButtonText","getFooter","find","modalsave","attr","getRoot","on","ModalEvents","hidden","remove","warningcheckbox","preventDefault","modalformdata","removeClass","modalradio","removeAttr","modalinput","modalradiochecked","val","addClass","save","querySelector","enablebulkinsert","formRadioData","formradio","value","formData","modalgrade","formgrade","formsave","show"],"mappings":";;;;;;;wmCAmCoB,WACVA,eAAiB,IAAIC,iBAC3BC,yBACAF,eAAeG,iBAQbD,uBAAyB,WACrBE,OAAS,CACX,QACAC,mCAAaD,OAAOE,SACpBD,mCAAaD,OAAOG,qDAEXC,OAAOC,SAAUL,QAG9BA,OAAOM,SAASC,QACZF,SAASG,iBAAiBD,OAAOE,MAAAA,UACvBC,QAAUC,EAAEC,OAAOC,QAAQC,mBAAUC,QAAQC,eAE/CN,WACgC,sBAA3BA,QAAQO,QAAQC,QAA+D,uBAA3BR,QAAQO,QAAQC,OAAkC,OACjGC,SAAWd,SAASe,iBAAiBN,mBAAUO,SAASF,UAE/B,uBAA3BT,QAAQO,QAAQC,OAEhBI,IAAIC,YAAY,CACZ,CAACC,IAAK,iBAAkBC,UAAW,0BACnC,CAACD,IAAK,sBAAuBC,UAAW,0BACxC,CAACD,IAAK,qBAAsBC,UAAW,0BACvC,CAACD,IAAK,SAAUC,UAAW,YAC5BC,MAAMC,gCACQC,QACTD,QAAQ,GACRA,QAAQ,GACRA,QAAQ,GACRA,QAAQ,IACR,KAEIR,SAASb,SAASuB,KACVA,GAAGC,SACHD,GAAGE,iBAIpBC,KAAKC,sBAAaC,WAIrBf,SAASb,SAASuB,KACTA,GAAGC,SACJD,GAAGE,gBAIZ,GAAgC,qBAA3BrB,QAAQO,QAAQC,QAA8D,sBAA3BR,QAAQO,QAAQC,OAAiC,OACtGiB,QAAU9B,SAASe,iBAAiBN,mBAAUO,SAASc,SACvDL,QAAsC,qBAA3BpB,QAAQO,QAAQC,OAEjCiB,QAAQ7B,SAASuB,KACbA,GAAGC,QAAUA,eAEiB,eAA3BpB,QAAQO,QAAQC,QAEvBI,IAAIC,YAAY,CACZ,CAACC,IAAK,aAAcC,UAAW,0BAC/B,CAACD,IAAK,OAAQC,UAAW,YAC1BC,MAAMC,iCACQS,OAAO,CAChBC,KAAMC,uBAAaC,MAAMC,YACzBC,KAAMC,mBAAUC,OAAO,oCAAqC,CACxDC,GAAI,kBACJC,KAAM,oBAEVC,MAAOnB,QAAQ,KAChBoB,MAAMC,QACLA,MAAMC,kBAAkBtB,QAAQ,IAChCqB,MAAME,YAAYC,KAAKrC,mBAAUO,SAAS+B,WAAWC,KAAK,YAAY,GAEtEL,MAAMM,UAAUC,GAAGC,sBAAYC,QAAQ,KACnCT,MAAMM,UAAUI,YAKpBV,MAAMM,UAAUC,GAAG,SAAUzC,mBAAUO,SAASsC,iBAC3ChD,OACGA,EAAEiD,iBACEjD,EAAEC,OAAOkB,QAAS,CAClBkB,MAAMM,UAAUH,KAAKrC,mBAAUO,SAASwC,eAAeC,YAAY,eACnEd,MAAMM,UAAUH,KAAKrC,mBAAUO,SAAS0C,YAAYC,WAAW,YAC/DhB,MAAMM,UAAUH,KAAKrC,mBAAUO,SAAS4C,YAAYD,WAAW,YAEzChB,MAAMM,UAAUH,KAAKrC,mBAAUO,SAAS6C,mBAAmBC,OAG7EnB,MAAME,YAAYC,KAAKrC,mBAAUO,SAAS+B,WAAWY,WAAW,iBAGpEhB,MAAMM,UAAUH,KAAKrC,mBAAUO,SAASwC,eAAeO,SAAS,eAChEpB,MAAMM,UAAUH,KAAKrC,mBAAUO,SAAS0C,YAAYV,KAAK,YAAY,GACrEL,MAAMM,UAAUH,KAAKrC,mBAAUO,SAAS4C,YAAYZ,KAAK,YAAY,GACrEL,MAAME,YAAYC,KAAKrC,mBAAUO,SAAS+B,WAAWC,KAAK,YAAY,MAKlFL,MAAMM,UAAUC,GAAG,SAAUzC,mBAAUO,SAAS0C,YAC3CpD,IACGA,EAAEiD,iBACFZ,MAAME,YAAYC,KAAKrC,mBAAUO,SAAS+B,WAAWY,WAAW,eAGxEhB,MAAMM,UAAUC,GAAGC,sBAAYa,MAAM,KAGjChE,SAASiE,cAAcxD,mBAAUO,SAASkD,kBAAkBzC,SAAU,QAChE0C,cAAgBxB,MAAMM,UAAUH,KAAKrC,mBAAUO,SAAS6C,mBAAmBC,MACjE9D,SAASiE,cAAcxD,mBAAUO,SAASoD,WAClDC,MAAQF,oBAEVG,SAAW3B,MAAMM,UAAUH,KAAKrC,mBAAUO,SAASuD,YAAYT,MACrE9D,SAASiE,cAAcxD,mBAAUO,SAASwD,WAAWH,MAAQC,SAC7DtE,SAASiE,cAAcxD,mBAAUO,SAASyD,UAAU/C,WAGxDiB,MAAM+B,OAEC/B,SACRhB,KAAKC,sBAAaC,cACtBF,KAAKC,sBAAaC"} \ No newline at end of file diff --git a/grade/report/singleview/amd/build/selectors.min.js b/grade/report/singleview/amd/build/selectors.min.js new file mode 100644 index 00000000000..7d902668018 --- /dev/null +++ b/grade/report/singleview/amd/build/selectors.min.js @@ -0,0 +1,3 @@ +define("gradereport_singleview/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;var name,value,_default={actions:{bulkaction:(name="role",value="bulkaction","[data-".concat(name,'="').concat(value,'"]'))},elements:{override:"input[type=checkbox][name^=override]",exclude:"input[type=checkbox][name^=exclude]",modalsave:'[data-action="save"]',warningcheckbox:'input[type="checkbox"]',modalformdata:".formdata",modalradio:'input[type="radio"]',modalinput:'input[type="text"]',modalradiochecked:'input[type="radio"]:checked',enablebulkinsert:'input[type="checkbox"][name^=bulk]',formradio:"select[name^=bulk]",modalgrade:".form-control",formgrade:'input[type="text"][name^=bulk]',formsave:'input[type="submit"]'}};return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=selectors.min.js.map \ No newline at end of file diff --git a/grade/report/singleview/amd/build/selectors.min.js.map b/grade/report/singleview/amd/build/selectors.min.js.map new file mode 100644 index 00000000000..a593675a117 --- /dev/null +++ b/grade/report/singleview/amd/build/selectors.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"selectors.min.js","sources":["../src/selectors.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 * Define all of the selectors we will be using on the grading interface.\n *\n * @module gradereport_singleview/selectors\n * @copyright 2022 Ilya Tregubov \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * A small helper function to build queryable data selectors.\n * @method getDataSelector\n * @param {String} name\n * @param {String} value\n * @return {string}\n */\nconst getDataSelector = (name, value) => {\n return `[data-${name}=\"${value}\"]`;\n};\n\nexport default {\n actions: {\n bulkaction: getDataSelector('role', 'bulkaction'),\n },\n elements: {\n override: 'input[type=checkbox][name^=override]',\n exclude: 'input[type=checkbox][name^=exclude]',\n modalsave: '[data-action=\"save\"]',\n warningcheckbox: 'input[type=\"checkbox\"]',\n modalformdata: '.formdata',\n modalradio: 'input[type=\"radio\"]',\n modalinput: 'input[type=\"text\"]',\n modalradiochecked: 'input[type=\"radio\"]:checked',\n enablebulkinsert: 'input[type=\"checkbox\"][name^=bulk]',\n formradio: 'select[name^=bulk]',\n modalgrade: '.form-control',\n formgrade: 'input[type=\"text\"][name^=bulk]',\n formsave: 'input[type=\"submit\"]',\n },\n};\n"],"names":["name","value","actions","bulkaction","elements","override","exclude","modalsave","warningcheckbox","modalformdata","modalradio","modalinput","modalradiochecked","enablebulkinsert","formradio","modalgrade","formgrade","formsave"],"mappings":"8JA8ByBA,KAAMC,eAIhB,CACXC,QAAS,CACLC,YANiBH,KAMW,OANLC,MAMa,6BALxBD,kBAASC,cAOzBG,SAAU,CACNC,SAAU,uCACVC,QAAS,sCACTC,UAAW,uBACXC,gBAAiB,yBACjBC,cAAe,YACfC,WAAY,sBACZC,WAAY,qBACZC,kBAAmB,8BACnBC,iBAAkB,qCAClBC,UAAW,qBACXC,WAAY,gBACZC,UAAW,iCACXC,SAAU"} \ No newline at end of file diff --git a/grade/report/singleview/amd/src/bulkactions.js b/grade/report/singleview/amd/src/bulkactions.js index 58344fb4934..0fa9bca8c33 100644 --- a/grade/report/singleview/amd/src/bulkactions.js +++ b/grade/report/singleview/amd/src/bulkactions.js @@ -26,6 +26,9 @@ import CustomEvents from "core/custom_interaction_events"; import ModalFactory from 'core/modal_factory'; import Templates from 'core/templates'; import ModalEvents from 'core/modal_events'; +import * as Str from 'core/str'; +import Notification from 'core/notification'; +import selectors from 'gradereport_singleview/selectors'; /** * Initialize module. @@ -52,102 +55,119 @@ const registerListenerEvents = () => { // Register events. events.forEach((event) => { document.addEventListener(event, async(e) => { - const trigger = e.target.closest('[data-role]'); + const trigger = e.target.closest(selectors.actions.bulkaction); + if (trigger) { - if ((trigger.dataset.role === 'overrideallgrades') || (trigger.dataset.role === 'overridenonegrades')) { - const overrideAll = document.querySelectorAll('input[type=checkbox][name^=override]'); + if ((trigger.dataset.action === 'overrideallgrades') || (trigger.dataset.action === 'overridenonegrades')) { + const override = document.querySelectorAll(selectors.elements.override); - if (trigger.dataset.role === 'overridenonegrades') { - const confirm = new M.core.confirm({ - title: M.util.get_string('removeoverride', 'gradereport_singleview'), - question: M.util.get_string('overridenoneconfirm', 'gradereport_singleview'), - noLabel: M.util.get_string('cancel', 'moodle'), - yesLabel: M.util.get_string('removeoverridesave', 'gradereport_singleview') - }); + if (trigger.dataset.action === 'overridenonegrades') { + // Alert for removing all grade overrides on page. + Str.get_strings([ + {key: 'removeoverride', component: 'gradereport_singleview'}, + {key: 'overridenoneconfirm', component: 'gradereport_singleview'}, + {key: 'removeoverridesave', component: 'gradereport_singleview'}, + {key: 'cancel', component: 'moodle'}, + ]).done((strings) => { + Notification.confirm( + strings[0], + strings[1], + strings[2], + strings[3], + () => { + // Uncheck each override checkbox - this will make grade and feedback input fields disabled. + override.forEach((el) => { + if (el.checked) { + el.click(); + } + }); + }); + }).fail(Notification.exception); - confirm.on('complete-yes', function () { - confirm.hide(); - confirm.destroy(); - - overrideAll.forEach(function (el) { - if (el.checked) { - el.click(); - } - }); - }, self); - confirm.show(); } else { - overrideAll.forEach(function (el) { + // Check each override checkbox - this will make grade and feedback input fields enabled. + override.forEach((el) => { if (!el.checked) { el.click(); } }); } - } else if ((trigger.dataset.role === 'excludeallgrades') || (trigger.dataset.role === 'excludenonegrades')) { - const excludeAll = document.querySelectorAll('input[type=checkbox][name^=exclude]'); - const checked = (trigger.dataset.role === 'excludeallgrades'); - excludeAll.forEach(function (el) { + } else if ((trigger.dataset.action === 'excludeallgrades') || (trigger.dataset.action === 'excludenonegrades')) { + const exclude = document.querySelectorAll(selectors.elements.exclude); + const checked = (trigger.dataset.action === 'excludeallgrades'); + // Uncheck or check each exclude checkbox. + exclude.forEach((el) => { el.checked = checked; }); - } else if (trigger.dataset.role === 'bulklegend') { - ModalFactory.create({ - type: ModalFactory.types.SAVE_CANCEL, - body: Templates.render('gradereport_singleview/bulkinsert', { - id: 'bulkinsertmodal', - name: 'bulkinsertmodal' - }), - title: 'Bulk insert', - }) - .then(function (modal) { - modal.setSaveButtonText('Save'); - modal.getFooter().find('[data-action="save"]').attr('disabled', true); + } else if (trigger.dataset.action === 'bulklegend') { + // Modal for bulk insert grades. + Str.get_strings([ + {key: 'bulklegend', component: 'gradereport_singleview'}, + {key: 'save', component: 'moodle'}, + ]).done((strings) => { + ModalFactory.create({ + type: ModalFactory.types.SAVE_CANCEL, + body: Templates.render('gradereport_singleview/bulkinsert', { + id: 'bulkinsertmodal', + name: 'bulkinsertmodal' + }), + title: strings[0], + }).then((modal) => { + modal.setSaveButtonText(strings[1]); + modal.getFooter().find(selectors.elements.modalsave).attr('disabled', true); - modal.getRoot().on(ModalEvents.hidden, function () { + modal.getRoot().on(ModalEvents.hidden, () => { modal.getRoot().remove(); }); - modal.getRoot().on('change', 'input[type="checkbox"]', + // We need to acknowledge that we understand risks of loosing data. + // Only when acknowledge checkbox is checked we allow selecting insert options. + modal.getRoot().on('change', selectors.elements.warningcheckbox, (e) => { e.preventDefault(); if (e.target.checked) { - modal.getRoot().find('.formdata').removeClass('dimmed_text'); - modal.getRoot().find('input[type="radio"]').removeAttr('disabled'); - modal.getRoot().find('input[type="text"]').removeAttr('disabled'); + modal.getRoot().find(selectors.elements.modalformdata).removeClass('dimmed_text'); + modal.getRoot().find(selectors.elements.modalradio).removeAttr('disabled'); + modal.getRoot().find(selectors.elements.modalinput).removeAttr('disabled'); - const formRadioData = modal.getRoot().find('input[type="radio"]:checked').val(); + const formRadioData = modal.getRoot().find(selectors.elements.modalradiochecked).val(); + // We allow saving grades only when all needed data present on form. if (formRadioData) { - modal.getFooter().find('[data-action="save"]').removeAttr('disabled'); + modal.getFooter().find(selectors.elements.modalsave).removeAttr('disabled'); } } else { - modal.getRoot().find('.formdata').addClass('dimmed_text'); - modal.getRoot().find('input[type="radio"]').attr('disabled', true); - modal.getRoot().find('input[type="text"]').attr('disabled', true); - modal.getFooter().find('[data-action="save"]').attr('disabled', true); + modal.getRoot().find(selectors.elements.modalformdata).addClass('dimmed_text'); + modal.getRoot().find(selectors.elements.modalradio).attr('disabled', true); + modal.getRoot().find(selectors.elements.modalinput).attr('disabled', true); + modal.getFooter().find(selectors.elements.modalsave).attr('disabled', true); } }); - modal.getRoot().on('change', 'input[type="radio"]', + // We allow saving grades only when all needed data present on form. + modal.getRoot().on('change', selectors.elements.modalradio, (e) => { e.preventDefault(); - modal.getFooter().find('[data-action="save"]').removeAttr('disabled'); + modal.getFooter().find(selectors.elements.modalsave).removeAttr('disabled'); }); - modal.getRoot().on(ModalEvents.save, function () { - document.querySelector('input[type="checkbox"][name^=bulk]').checked = true; - - const formRadioData = modal.getRoot().find('input[type="radio"]:checked').val(); - const $select = document.querySelector('select[name^=bulk]'); + modal.getRoot().on(ModalEvents.save, () => { + // When save button is clicked in modal form we insert data from modal + // into preexisted hidden bulk insert form and Save button for table form. + document.querySelector(selectors.elements.enablebulkinsert).checked = true; + const formRadioData = modal.getRoot().find(selectors.elements.modalradiochecked).val(); + const $select = document.querySelector(selectors.elements.formradio); $select.value = formRadioData; - const formData = modal.getRoot().find('.form-control').val(); - document.querySelector('input[type="text"][name^=bulk]').value = formData; - document.querySelector('input[type="submit"]').click(); + const formData = modal.getRoot().find(selectors.elements.modalgrade).val(); + document.querySelector(selectors.elements.formgrade).value = formData; + document.querySelector(selectors.elements.formsave).click(); }); modal.show(); return modal; - }); + }).fail(Notification.exception); + }).fail(Notification.exception); } } }); diff --git a/grade/report/singleview/amd/src/selectors.js b/grade/report/singleview/amd/src/selectors.js new file mode 100644 index 00000000000..b985ffe2743 --- /dev/null +++ b/grade/report/singleview/amd/src/selectors.js @@ -0,0 +1,54 @@ +// 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 . + +/** + * Define all of the selectors we will be using on the grading interface. + * + * @module gradereport_singleview/selectors + * @copyright 2022 Ilya Tregubov + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * A small helper function to build queryable data selectors. + * @method getDataSelector + * @param {String} name + * @param {String} value + * @return {string} + */ +const getDataSelector = (name, value) => { + return `[data-${name}="${value}"]`; +}; + +export default { + actions: { + bulkaction: getDataSelector('role', 'bulkaction'), + }, + elements: { + override: 'input[type=checkbox][name^=override]', + exclude: 'input[type=checkbox][name^=exclude]', + modalsave: '[data-action="save"]', + warningcheckbox: 'input[type="checkbox"]', + modalformdata: '.formdata', + modalradio: 'input[type="radio"]', + modalinput: 'input[type="text"]', + modalradiochecked: 'input[type="radio"]:checked', + enablebulkinsert: 'input[type="checkbox"][name^=bulk]', + formradio: 'select[name^=bulk]', + modalgrade: '.form-control', + formgrade: 'input[type="text"][name^=bulk]', + formsave: 'input[type="submit"]', + }, +}; diff --git a/grade/report/singleview/classes/local/ui/bulk_insert.php b/grade/report/singleview/classes/local/ui/bulk_insert.php index ca3ce2de1c7..a958276c5e8 100644 --- a/grade/report/singleview/classes/local/ui/bulk_insert.php +++ b/grade/report/singleview/classes/local/ui/bulk_insert.php @@ -97,7 +97,6 @@ class bulk_insert extends element { ['value' => 'blanks', 'name' => get_string('blanks', 'gradereport_singleview'), 'selected' => true], ], 'valuename' => $this->insertname, - 'valuelabel' => get_string('bulkinsertvalue', 'gradereport_singleview'), 'valuefield' => $text->html() ]; diff --git a/grade/report/singleview/classes/output/action_bar.php b/grade/report/singleview/classes/output/action_bar.php index fb190f3e44d..2a694a10ee4 100644 --- a/grade/report/singleview/classes/output/action_bar.php +++ b/grade/report/singleview/classes/output/action_bar.php @@ -83,10 +83,10 @@ class action_bar extends \core_grades\output\action_bar { 'displaylabel' => true, 'userselectactive' => $this->itemtype === 'user', 'gradeselectactive' => $this->itemtype === 'grade', - 'gradezerolink' => new moodle_url('/grade/report/singleview/index.php', - ['id' => $courseid, 'item' => 'grade_select']), - 'userzerolink' => new moodle_url('/grade/report/singleview/index.php', - ['id' => $courseid, 'item' => 'user_select']) + 'gradezerolink' => (new moodle_url('/grade/report/singleview/index.php', + ['id' => $courseid, 'item' => 'grade_select']))->out(false), + 'userzerolink' => (new moodle_url('/grade/report/singleview/index.php', + ['id' => $courseid, 'item' => 'user_select']))->out(false) ]; $data['groupselector'] = $this->report->group_selector; diff --git a/grade/report/singleview/classes/report/singleview.php b/grade/report/singleview/classes/report/singleview.php index 58cb86adddd..20271e91154 100644 --- a/grade/report/singleview/classes/report/singleview.php +++ b/grade/report/singleview/classes/report/singleview.php @@ -189,7 +189,7 @@ class singleview extends grade_report { foreach ($options as $type => $option) { $action = new \action_menu_link_secondary(new \moodle_url('#'), null, $option, - ['data-role' => $type]); + ['data-action' => $type, 'data-role' => 'bulkaction']); $menu->add($action); } $menu->attributes['class'] .= ' float-left my-auto'; diff --git a/grade/report/singleview/lang/en/gradereport_singleview.php b/grade/report/singleview/lang/en/gradereport_singleview.php index 2335905fdf2..cf61746e16a 100644 --- a/grade/report/singleview/lang/en/gradereport_singleview.php +++ b/grade/report/singleview/lang/en/gradereport_singleview.php @@ -30,7 +30,6 @@ $string['assessmentname'] = 'Grade item'; $string['blanks'] = 'Empty grades'; $string['bulkappliesto'] = 'For'; $string['bulkinsertvalue'] = 'Insert value'; -$string['bulkinsertvaluemodal'] = 'Insert value modal'; $string['bulklegend'] = 'Bulk insert'; $string['bulkchoice'] = 'For which grades do you want to insert?'; $string['bulkperform'] = 'Perform bulk insert'; @@ -72,9 +71,8 @@ $string['selectuser'] = 'Select user...'; $string['singleview:view'] = 'View report'; $string['summarygrade'] = 'A table of users, with columns for range, grade, feedback, and whether to override or exclude a particular grade.'; $string['summaryuser'] = 'A table of grade items, with columns for grade category, range, grade, feedback, and whether to override or exclude a particular grade.'; -$string['unsavedataalert'] = 'If you have unsave changes in grades table, you might lose some data when chosing "All grades" and click Save.'; -$string['unsavedataconfirm'] = 'I understand that my unsaved data might be lost'; -$string['users'] = 'Users'; +$string['unsavedataalert'] = 'You have unsaved changes in the grades table, you will lose these changes if you proceed with the bulk insert.'; +$string['unsavedataconfirm'] = 'I understand that my unsaved changes will be lost.'; $string['userselect'] = 'Select activity'; $string['ariareporttype'] = 'Select a report type to view'; @@ -84,6 +82,7 @@ $string['selectagrade'] = 'Select a grade item'; $string['selectuserinstructions'] = 'By selecting a user you can view the grades by activity'; $string['selectgradeinstructions'] = 'Select items to grade...'; $string['selectgradeitemlink'] = 'Click to select a grade item'; +$string['unsaveddatawarning'] = 'Unsaved data warning'; $string['whattoview'] = 'What would you like to view'; $string['whattoviewselect'] = 'Select to view by users or grade items'; diff --git a/grade/report/singleview/styles.css b/grade/report/singleview/styles.css index e2cd14128c9..ecacaf8fa7e 100644 --- a/grade/report/singleview/styles.css +++ b/grade/report/singleview/styles.css @@ -134,7 +134,14 @@ .path-grade-report-singleview input[type=checkbox] { width: 22px; height: 21px; - margin: 11.5px auto 11.5px auto; + margin: 11.5px 11.5px 11.5px auto; +} + +#bulkinsertmodal { + width: 181px; + height: 39px; + top: 309px; + border-radius: 4px; } .path-grade-report-singleview .singleview_bulk > fieldset { diff --git a/grade/report/singleview/templates/action_bar.mustache b/grade/report/singleview/templates/action_bar.mustache index 27b80c89edb..f2e80c0c0e5 100644 --- a/grade/report/singleview/templates/action_bar.mustache +++ b/grade/report/singleview/templates/action_bar.mustache @@ -16,6 +16,59 @@ }} {{! @template gradereport_singleview/action_bar + + Context variables required for this template: + * generalnavselector - The data object containing the required properties to render the general navigation selector. + * groupselector - (optional) HTML that outputs the group selector + * itemselector - (optional) HTML that outputs the user or grade item selector + * pagetoggler - (optional) HTML that outputs the user/grade item view toggler + * bulkactions - (optional) HTML that outputs the bulk actione menu + + Example context (json): + { + "generalnavselector": { + "name": "Gradebook tertiary navigation selector", + "value": "opt2", + "baseid": "select-menu56789", + "selectedoption": "Gradebook setup", + "options": [ + { + "selected": false, + "isgroup": { + "name": "View", + "id": "select-menu-group1", + "options": [ + { + "name": "Grader report", + "value": "opt1", + "id": "select-menu-option1", + "selected": false + } + ] + } + }, + { + "selected": false, + "isgroup": { + "name": "Setup", + "id": "select-menu-group2", + "options": [ + { + "name": "Gradebook setup", + "value": "opt2", + "id": "select-menu-option2", + "selected": true + } + ] + } + } + ] + }, + "groupselector": "
", + "itemselector": "
", + "pagetoggler": "
", + "bulkactions": "
" + } }}
diff --git a/grade/report/singleview/templates/bulkinsert.mustache b/grade/report/singleview/templates/bulkinsert.mustache index e7e7dae739d..c6ddedeaf0b 100644 --- a/grade/report/singleview/templates/bulkinsert.mustache +++ b/grade/report/singleview/templates/bulkinsert.mustache @@ -14,16 +14,17 @@ {{! @template core_message/send_bulk_message Template for the bulk insert grades modal. - Context variables required for this template: - None + Example context (json): { + "name": "bulksinsertmodal", + "id": "bulksinsertmodal" } }}
-
+
{{#str}}unsavedataalert, gradereport_singleview{{/str}} - + {{#str}}unsaveddatawarning, gradereport_singleview{{/str}}
-
-

- {{#str}}bulkchoice, gradereport_singleview{{/str}} -

- - -
-

- + {{#str}}bulkchoice, gradereport_singleview{{/str}} +
+ + +

{{#str}}bulkinsertvalue, gradereport_singleview{{/str}}

- +
diff --git a/grade/report/singleview/templates/grade_item_selector.mustache b/grade/report/singleview/templates/grade_item_selector.mustache index 55c9d56a097..890711a02ae 100644 --- a/grade/report/singleview/templates/grade_item_selector.mustache +++ b/grade/report/singleview/templates/grade_item_selector.mustache @@ -25,7 +25,7 @@ { "courseid": "2", "selectedoption": { - "text": "Grade item 1", + "text": "Grade item 1" } } }} diff --git a/grade/report/singleview/templates/page_toggler.mustache b/grade/report/singleview/templates/page_toggler.mustache index c06187e9793..25f01e5c195 100644 --- a/grade/report/singleview/templates/page_toggler.mustache +++ b/grade/report/singleview/templates/page_toggler.mustache @@ -33,16 +33,16 @@

{{#str}}viewby, gradereport_singleview{{/str}}

{{/displaylabel}}
- {{#str}}users{{/str}} - Grader report" in the course gradebook + Given I navigate to "View > Grader report" in the course gradebook And I follow "Single view for Test assignment one" And I click on "Actions" "link" When I click on "Bulk insert" "link" And the "Empty grades" "radio" should be disabled And the "All grades" "radio" should be disabled - And the "Insert value modal" "field" should be disabled + And the "[name=bulkinsertmodal]" "css_element" should be disabled And the "[data-action=save]" "css_element" should be disabled - And I click on "I understand that my unsaved data might be lost" "checkbox" + And I click on "I understand that my unsaved changes will be lost." "checkbox" And the "Empty grades" "radio" should be enabled And the "All grades" "radio" should be enabled - And the "Insert value modal" "field" should be enabled + And the "[name=bulkinsertmodal]" "css_element" should be enabled And the "[data-action=save]" "css_element" should be disabled And I click on "Empty grades" "radio" And the "Empty grades" "radio" should be enabled And the "All grades" "radio" should be enabled - And the "Insert value modal" "field" should be enabled - And the "[data-action=save]" "css_element" should be enabled + And the "[name=bulkinsertmodal]" "css_element" should be enabled + Then the "[data-action=save]" "css_element" should be enabled Scenario: I can bulk insert grades and check their override flags for grade view. - Given I am on the "Test assignment one" "assign activity" page logged in as teacher1 + Given I am on the "Test assignment one" "assign activity" page And I follow "View all submissions" And I click on "Grade" "link" in the "Student 1" "table_row" And I set the following fields to these values: @@ -61,13 +61,13 @@ Feature: We can bulk insert grades for students in a course And I am on "Course 1" course homepage with editing mode on And I navigate to "View > Grader report" in the course gradebook And I follow "Single view for Test assignment one" - Then the field "Grade for Student 1" matches value "50.00" + And the field "Grade for Student 1" matches value "50.00" And the field "Override for Student 1" matches value "0" And I click on "Actions" "link" And I click on "Bulk insert" "link" - And I click on "I understand that my unsaved data might be lost" "checkbox" + And I click on "I understand that my unsaved changes will be lost." "checkbox" And I click on "Empty grades" "radio" - And I set the field "Insert value modal" to "1.0" + And I set the field "Insert value" to "1.0" And I click on "Save" "button" in the ".modal-dialog" "css_element" And the field "Grade for Student 1" matches value "50.00" And the field "Override for Student 1" matches value "0" @@ -79,10 +79,10 @@ Feature: We can bulk insert grades for students in a course And the field "Override for Student 4" matches value "1" And I click on "Actions" "link" - And I click on "Bulk insert" "link" - And I click on "I understand that my unsaved data might be lost" "checkbox" + When I click on "Bulk insert" "link" + And I click on "I understand that my unsaved changes will be lost." "checkbox" And I click on "All grades" "radio" - And I set the field "Insert value modal" to "2.0" + And I set the field "Insert value" to "2.0" And I click on "Save" "button" in the ".modal-dialog" "css_element" And the field "Grade for Student 1" matches value "2.00" And the field "Override for Student 1" matches value "1" @@ -91,10 +91,10 @@ Feature: We can bulk insert grades for students in a course And the field "Grade for Student 3" matches value "2.00" And the field "Override for Student 3" matches value "1" And the field "Grade for Student 4" matches value "2.00" - And the field "Override for Student 4" matches value "1" + Then the field "Override for Student 4" matches value "1" Scenario: I can bulk insert grades and check their override flags for user view. - Given I am on the "Test assignment two" "assign activity" page logged in as teacher1 + Given I am on the "Test assignment two" "assign activity" page And I follow "View all submissions" And I click on "Grade" "link" in the "Student 1" "table_row" And I set the following fields to these values: @@ -102,16 +102,14 @@ Feature: We can bulk insert grades for students in a course And I press "Save changes" And I am on "Course 1" course homepage with editing mode on And I navigate to "View > Grader report" in the course gradebook - # And I click on "input[title='Dock Navigation block']" "css_element" - # And I click on "input[title='Dock Administration block']" "css_element" And I follow "Single view for Student 1" - Then the field "Grade for Test assignment two" matches value "50.00" + And the field "Grade for Test assignment two" matches value "50.00" And the field "Override for Test assignment two" matches value "0" And I click on "Actions" "link" - And I click on "Bulk insert" "link" - And I click on "I understand that my unsaved data might be lost" "checkbox" + When I click on "Bulk insert" "link" + And I click on "I understand that my unsaved changes will be lost." "checkbox" And I click on "Empty grades" "radio" - And I set the field "Insert value modal" to "1.0" + And I set the field "Insert value" to "1.0" And I click on "Save" "button" in the ".modal-dialog" "css_element" And the field "Grade for Test assignment two" matches value "50.00" And the field "Override for Test assignment two" matches value "0" @@ -120,21 +118,19 @@ Feature: We can bulk insert grades for students in a course And the field "Grade for Test assignment three" matches value "1.00" And the field "Override for Test assignment three" matches value "1" And the field "Grade for Test assignment four" matches value "1.00" - And the field "Override for Test assignment four" matches value "1" + Then the field "Override for Test assignment four" matches value "1" Scenario: I can not update grades if the value is out of bounds. - Given I am on the "Course 1" course page logged in as teacher1 - And I turn editing mode on - And I navigate to "View > Grader report" in the course gradebook + Given I navigate to "View > Grader report" in the course gradebook And I follow "Single view for Test assignment one" And I click on "Actions" "link" - And I click on "Bulk insert" "link" - And I click on "I understand that my unsaved data might be lost" "checkbox" + When I click on "Bulk insert" "link" + And I click on "I understand that my unsaved changes will be lost." "checkbox" And I click on "Empty grades" "radio" - And I set the field "Insert value modal" to "-1" + And I set the field "Insert value" to "-1" And I click on "Save" "button" in the ".modal-dialog" "css_element" - Then I should see "The grade entered for Test assignment one for Student 1 is less than the minimum allowed" + And I should see "The grade entered for Test assignment one for Student 1 is less than the minimum allowed" And I should see "The grade entered for Test assignment one for Student 2 is less than the minimum allowed" And I should see "The grade entered for Test assignment one for Student 3 is less than the minimum allowed" And I should see "The grade entered for Test assignment one for Student 4 is less than the minimum allowed" - And I should see "Grades were set for 0 items" + Then I should see "Grades were set for 0 items" diff --git a/grade/report/singleview/tests/behat/gradeitemsearch.feature b/grade/report/singleview/tests/behat/gradeitemsearch.feature index 935278baaab..6fd0686a6f7 100644 --- a/grade/report/singleview/tests/behat/gradeitemsearch.feature +++ b/grade/report/singleview/tests/behat/gradeitemsearch.feature @@ -21,7 +21,7 @@ Feature: Given we have opted to search for a grade item, Lets find and search th Scenario: A teacher can search for and find a grade item to view Given I navigate to "View > Single view" in the course gradebook - And I click on "Grade items" "link" in the ".singleindex" "css_element" + And I click on "Grade items" "link" in the ".page-toggler" "css_element" When I click on ".gradewidget" "css_element" Then I confirm "Test assignment one" in "Select a grade item" search within the gradebook widget exists And I confirm "Test assignment two" in "Select a grade item" search within the gradebook widget exists diff --git a/grade/report/singleview/tests/behat/reportswitching.feature b/grade/report/singleview/tests/behat/reportswitching.feature index 93a2a3d3cca..41b872be791 100644 --- a/grade/report/singleview/tests/behat/reportswitching.feature +++ b/grade/report/singleview/tests/behat/reportswitching.feature @@ -20,7 +20,7 @@ Feature: Given we land on the index page, select what type of report we wish to Scenario: I switch between the two report types within singleview Given I navigate to "View > Single view" in the course gradebook - And I click on "Grade items" "link" in the ".singleindex" "css_element" + And I click on "Grade items" "link" in the ".page-toggler" "css_element" When I click on ".gradewidget" "css_element" Then I wait until "Select a grade item" "dialogue" exists And I click on "Close" "button" in the "Select a grade item" "dialogue" diff --git a/grade/report/singleview/tests/behat/singleview.feature b/grade/report/singleview/tests/behat/singleview.feature index 71c75167f14..9e9d9f55d21 100644 --- a/grade/report/singleview/tests/behat/singleview.feature +++ b/grade/report/singleview/tests/behat/singleview.feature @@ -59,7 +59,7 @@ Feature: We can use Single view Scenario: I can update grades, add feedback and exclude grades. Given I navigate to "View > Single view" in the course gradebook - And I click on "User" "link" in the ".singleindex" "css_element" + And I click on "Users" "link" And I click on "Student" in the "user" search widget And I turn editing mode on And I set the field "Override for Test assignment one" to "1" @@ -99,7 +99,7 @@ Feature: We can use Single view And I log in as "teacher2" And I am on "Course 1" course homepage Given I navigate to "View > Single view" in the course gradebook - And I click on "User" "link" in the ".singleindex" "css_element" + And I click on "Users" "link" And I click on "Student" in the "user" search widget And I turn editing mode on And the "Exclude for Test assignment one" "checkbox" should be disabled @@ -118,9 +118,9 @@ Feature: We can use Single view When I turn editing mode on And I click on "Actions" "link" And I click on "Bulk insert" "link" - And I click on "I understand that my unsaved data might be lost" "checkbox" + And I click on "I understand that my unsaved changes will be lost." "checkbox" And I click on "All grades" "radio" - And I set the field "Insert value modal" to "1.0" + And I set the field "Insert value" to "1.0" And I click on "Save" "button" in the ".modal-dialog" "css_element" Then I should see "Grades were set for 6 items" @@ -133,12 +133,12 @@ Feature: We can use Single view When I turn editing mode on And I click on "Actions" "link" And I click on "Bulk insert" "link" - And I click on "I understand that my unsaved data might be lost" "checkbox" + And I click on "I understand that my unsaved changes will be lost." "checkbox" And I click on "All grades" "radio" - And I set the field "Insert value modal" to "1#25" + And I set the field "Insert value" to "1#25" And I click on "Save" "button" in the ".modal-dialog" "css_element" Then I should see "Grades were set for 6 items" - # Custome scale, cast to int + # Custom scale, cast to int And the field "Grade for new grade item 1" matches value "Disappointing" # Value grade, float with custom decsep. And the field "Grade for Test assignment one" matches value "1#25" diff --git a/grade/report/singleview/tests/behat/usersearch.feature b/grade/report/singleview/tests/behat/usersearch.feature index b59a6d2083a..a79d3f38973 100644 --- a/grade/report/singleview/tests/behat/usersearch.feature +++ b/grade/report/singleview/tests/behat/usersearch.feature @@ -21,7 +21,7 @@ Feature: Within the singleview report, a teacher can search for users. Scenario: A teacher can search for and find a user to view Given I navigate to "View > Single view" in the course gradebook - When I click on "User" "link" in the ".singleindex" "css_element" + When I click on "Users" "link" in the ".page-toggler" "css_element" And I wait until the page is ready And I click on ".userwidget" "css_element" Then I confirm "Student 1" in "Select a user" search within the gradebook widget exists