From 35cabfcc7ea8b2ed81a1bfe3eb7fd17430491600 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Thu, 8 Aug 2024 07:20:45 +1000 Subject: [PATCH] MDL-80750 core: Use roving tabindex to manage focus for bulk actions Implement roving focus for toolbars. See https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/ --- .../build/bulkactions/edit/tree/move.min.js | 2 +- .../bulkactions/edit/tree/move.min.js.map | 2 +- grade/amd/src/bulkactions/edit/tree/move.js | 4 +- lib/amd/build/bulkactions/bulk_action.min.js | 2 +- .../build/bulkactions/bulk_action.min.js.map | 2 +- lib/amd/build/bulkactions/bulk_actions.min.js | 2 +- .../build/bulkactions/bulk_actions.min.js.map | 2 +- lib/amd/src/bulkactions/bulk_action.js | 5 +- lib/amd/src/bulkactions/bulk_actions.js | 6 +- .../bulkactions/bulk_action_trigger.mustache | 5 +- .../bulkactions/bulk_actions.mustache | 1 + .../build/bulkactions/grading/delete.min.js | 2 +- .../bulkactions/grading/delete.min.js.map | 2 +- .../build/bulkactions/grading/extend.min.js | 2 +- .../bulkactions/grading/extend.min.js.map | 2 +- .../bulkactions/grading/general_action.min.js | 2 +- .../grading/general_action.min.js.map | 2 +- .../build/bulkactions/grading/message.min.js | 2 +- .../bulkactions/grading/message.min.js.map | 2 +- .../grading/setmarkingallocation.min.js | 2 +- .../grading/setmarkingallocation.min.js.map | 2 +- .../grading/setmarkingworkflowstate.min.js | 2 +- .../setmarkingworkflowstate.min.js.map | 2 +- .../amd/src/bulkactions/grading/delete.js | 3 +- .../amd/src/bulkactions/grading/extend.js | 3 +- .../src/bulkactions/grading/general_action.js | 3 +- .../amd/src/bulkactions/grading/message.js | 3 +- .../grading/setmarkingallocation.js | 3 +- .../grading/setmarkingworkflowstate.js | 3 +- .../grading/bulk_delete_trigger.mustache | 4 +- .../grading/bulk_extend_trigger.mustache | 4 +- .../bulk_general_action_trigger.mustache | 4 +- .../grading/bulk_message_trigger.mustache | 4 +- ...bulk_setmarkingallocation_trigger.mustache | 4 +- ...k_setmarkingworkflowstate_trigger.mustache | 4 +- theme/boost/amd/build/aria.min.js | 2 +- theme/boost/amd/build/aria.min.js.map | 2 +- theme/boost/amd/src/aria.js | 71 +++++++++++++------ 38 files changed, 114 insertions(+), 60 deletions(-) diff --git a/grade/amd/build/bulkactions/edit/tree/move.min.js b/grade/amd/build/bulkactions/edit/tree/move.min.js index 429d140cec5..70d8fbe4eda 100644 --- a/grade/amd/build/bulkactions/edit/tree/move.min.js +++ b/grade/amd/build/bulkactions/edit/tree/move.min.js @@ -1,3 +1,3 @@ -define("core_grades/bulkactions/edit/tree/move",["exports","core/bulkactions/bulk_action","core/str","core/modal_save_cancel","core/templates","core/ajax","core/modal_events","core_grades/bulkactions/edit/tree/move_options_tree"],(function(_exports,_bulk_action,_str,_modal_save_cancel,_templates,_ajax,_modal_events,_move_options_tree){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_templates=_interopRequireDefault(_templates),_ajax=_interopRequireDefault(_ajax),_modal_events=_interopRequireDefault(_modal_events),_move_options_tree=_interopRequireDefault(_move_options_tree);const Selectors_editTreeForm="#gradetreeform",Selectors_bulkMoveInput='input[name="bulkmove"]',Selectors_bulkMoveAfterInput='input[name="moveafter"]';class GradebookEditTreeBulkMove extends _bulk_action.default{constructor(courseId){super(),_defineProperty(this,"courseId",null),_defineProperty(this,"moveOptionsTree",null),_defineProperty(this,"gradeTree",null),this.courseId=courseId}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="move"]'}async triggerBulkAction(){const modal=await this.showModal();this.registerCustomListenerEvents(modal)}async renderBulkActionTrigger(showInDropdown){return _templates.default.render("core_grades/bulkactions/edit/tree/bulk_move_trigger",{showindropdown:showInDropdown})}async registerCustomListenerEvents(modal){await modal.getBody(),modal.getRoot().on(_modal_events.default.shown,(()=>{this.moveOptionsTree=new _move_options_tree.default((()=>{modal.setButtonDisabled("save",!1)}))})),modal.getRoot().on(_modal_events.default.hidden,(()=>{modal.destroy()})),modal.getRoot().on(_modal_events.default.save,(()=>{this.moveOptionsTree&&this.moveOptionsTree.selectedMoveOption&&(document.querySelector(Selectors_bulkMoveInput).value=1,document.querySelector(Selectors_bulkMoveAfterInput).value=this.moveOptionsTree.selectedMoveOption.dataset.id,document.querySelector(Selectors_editTreeForm).submit())}))}fetchGradeTree(){const request={methodname:"core_grades_get_grade_tree",args:{courseid:this.courseId}};return _ajax.default.call([request])[0]}async renderModalBody(){return null===this.gradeTree&&(this.gradeTree=await this.fetchGradeTree()),_templates.default.render("core_grades/bulkactions/edit/tree/bulk_move_grade_tree",JSON.parse(this.gradeTree))}async showModal(){const modal=await _modal_save_cancel.default.create({title:await(0,_str.get_string)("movesitems","grades"),body:await this.renderModalBody(),buttons:{save:await(0,_str.get_string)("move")},large:!0});return modal.setButtonDisabled("save",!0),modal.show(),modal}}return _exports.default=GradebookEditTreeBulkMove,_exports.default})); +define("core_grades/bulkactions/edit/tree/move",["exports","core/bulkactions/bulk_action","core/str","core/modal_save_cancel","core/templates","core/ajax","core/modal_events","core_grades/bulkactions/edit/tree/move_options_tree"],(function(_exports,_bulk_action,_str,_modal_save_cancel,_templates,_ajax,_modal_events,_move_options_tree){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_templates=_interopRequireDefault(_templates),_ajax=_interopRequireDefault(_ajax),_modal_events=_interopRequireDefault(_modal_events),_move_options_tree=_interopRequireDefault(_move_options_tree);const Selectors_editTreeForm="#gradetreeform",Selectors_bulkMoveInput='input[name="bulkmove"]',Selectors_bulkMoveAfterInput='input[name="moveafter"]';class GradebookEditTreeBulkMove extends _bulk_action.default{constructor(courseId){super(),_defineProperty(this,"courseId",null),_defineProperty(this,"moveOptionsTree",null),_defineProperty(this,"gradeTree",null),this.courseId=courseId}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="move"]'}async triggerBulkAction(){const modal=await this.showModal();this.registerCustomListenerEvents(modal)}async renderBulkActionTrigger(showInDropdown,index){return _templates.default.render("core_grades/bulkactions/edit/tree/bulk_move_trigger",{showindropdown:showInDropdown,isfirst:0===index})}async registerCustomListenerEvents(modal){await modal.getBody(),modal.getRoot().on(_modal_events.default.shown,(()=>{this.moveOptionsTree=new _move_options_tree.default((()=>{modal.setButtonDisabled("save",!1)}))})),modal.getRoot().on(_modal_events.default.hidden,(()=>{modal.destroy()})),modal.getRoot().on(_modal_events.default.save,(()=>{this.moveOptionsTree&&this.moveOptionsTree.selectedMoveOption&&(document.querySelector(Selectors_bulkMoveInput).value=1,document.querySelector(Selectors_bulkMoveAfterInput).value=this.moveOptionsTree.selectedMoveOption.dataset.id,document.querySelector(Selectors_editTreeForm).submit())}))}fetchGradeTree(){const request={methodname:"core_grades_get_grade_tree",args:{courseid:this.courseId}};return _ajax.default.call([request])[0]}async renderModalBody(){return null===this.gradeTree&&(this.gradeTree=await this.fetchGradeTree()),_templates.default.render("core_grades/bulkactions/edit/tree/bulk_move_grade_tree",JSON.parse(this.gradeTree))}async showModal(){const modal=await _modal_save_cancel.default.create({title:await(0,_str.get_string)("movesitems","grades"),body:await this.renderModalBody(),buttons:{save:await(0,_str.get_string)("move")},large:!0});return modal.setButtonDisabled("save",!0),modal.show(),modal}}return _exports.default=GradebookEditTreeBulkMove,_exports.default})); //# sourceMappingURL=move.min.js.map \ No newline at end of file diff --git a/grade/amd/build/bulkactions/edit/tree/move.min.js.map b/grade/amd/build/bulkactions/edit/tree/move.min.js.map index 60a52c4ce88..9c5f17ec64c 100644 --- a/grade/amd/build/bulkactions/edit/tree/move.min.js.map +++ b/grade/amd/build/bulkactions/edit/tree/move.min.js.map @@ -1 +1 @@ -{"version":3,"file":"move.min.js","sources":["../../../../src/bulkactions/edit/tree/move.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 * Class that defines the bulk move action in the gradebook setup page.\n *\n * @module core_grades/bulkactions/edit/tree/move\n * @copyright 2023 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport {get_string as getString} from 'core/str';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport Templates from 'core/templates';\nimport Ajax from 'core/ajax';\nimport ModalEvents from 'core/modal_events';\nimport MoveOptionsTree from 'core_grades/bulkactions/edit/tree/move_options_tree';\n\n/** @constant {Object} The object containing the relevant selectors. */\nconst Selectors = {\n editTreeForm: '#gradetreeform',\n bulkMoveInput: 'input[name=\"bulkmove\"]',\n bulkMoveAfterInput: 'input[name=\"moveafter\"]'\n};\n\nexport default class GradebookEditTreeBulkMove extends BulkAction {\n\n /** @property {int|null} courseId The course ID. */\n courseId = null;\n\n /** @property {MoveOptionsTree|null} moveOptionsTree The move options tree object. */\n moveOptionsTree = null;\n\n /** @property {string|null} gradeTree The grade tree structure. */\n gradeTree = null;\n\n /**\n * The class constructor.\n *\n * @param {int} courseId The course ID.\n * @returns {void}\n */\n constructor(courseId) {\n super();\n this.courseId = courseId;\n }\n\n /**\n * Defines the selector of the element that triggers the bulk move action.\n *\n * @returns {string} The bulk move action trigger selector.\n */\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"move\"]';\n }\n\n /**\n * Defines the behavior once the bulk move action is triggered.\n *\n * @method executeBulkAction\n * @returns {void}\n */\n async triggerBulkAction() {\n const modal = await this.showModal();\n this.registerCustomListenerEvents(modal);\n }\n\n /**\n * Renders the bulk move action trigger element.\n *\n * @method renderBulkActionTrigger\n * @param {boolean} showInDropdown Whether the action is displayed under a 'More' dropdown or as a separate button.\n * @returns {Promise} The bulk move action trigger promise\n */\n async renderBulkActionTrigger(showInDropdown) {\n return Templates.render('core_grades/bulkactions/edit/tree/bulk_move_trigger', {\n showindropdown: showInDropdown,\n });\n }\n\n /**\n * Register custom event listeners.\n *\n * @method registerCustomClickListenerEvents\n * @param {Object} modal The modal object.\n * @returns {void}\n */\n async registerCustomListenerEvents(modal) {\n await modal.getBody();\n // Initialize the move options tree once the modal is shown.\n modal.getRoot().on(ModalEvents.shown, () => {\n this.moveOptionsTree = new MoveOptionsTree(() => {\n // Enable the 'Move' action button once something is selected.\n modal.setButtonDisabled('save', false);\n });\n });\n // Destroy the modal once it is hidden.\n modal.getRoot().on(ModalEvents.hidden, () => {\n modal.destroy();\n });\n // Define the move action event.\n modal.getRoot().on(ModalEvents.save, () => {\n // Make sure that a move option is selected.\n if (this.moveOptionsTree && this.moveOptionsTree.selectedMoveOption) {\n // Set the relevant form values.\n document.querySelector(Selectors.bulkMoveInput).value = 1;\n document.querySelector(Selectors.bulkMoveAfterInput).value = this.moveOptionsTree.selectedMoveOption.dataset.id;\n // Submit the form.\n document.querySelector(Selectors.editTreeForm).submit();\n }\n });\n }\n\n /**\n * Fetch the grade tree structure for the current course.\n *\n * @method fetchGradeTree\n * @returns {Promise} The grade tree promise\n */\n fetchGradeTree() {\n const request = {\n methodname: 'core_grades_get_grade_tree',\n args: {\n courseid: this.courseId,\n },\n };\n return Ajax.call([request])[0];\n }\n\n /**\n * Renders the bulk move modal body.\n *\n * @method renderModalBody\n * @returns {Promise} The modal body promise\n */\n async renderModalBody() {\n // We need to fetch the grade tree structure only once.\n if (this.gradeTree === null) {\n this.gradeTree = await this.fetchGradeTree();\n }\n\n return Templates.render('core_grades/bulkactions/edit/tree/bulk_move_grade_tree',\n JSON.parse(this.gradeTree));\n }\n\n /**\n * Show the bulk move modal.\n *\n * @method showModal\n * @returns {Promise} The modal promise\n */\n async showModal() {\n const modal = await ModalSaveCancel.create({\n title: await getString('movesitems', 'grades'),\n body: await this.renderModalBody(),\n buttons: {\n save: await getString('move')\n },\n large: true,\n });\n // Disable the 'Move' action button until something is selected.\n modal.setButtonDisabled('save', true);\n modal.show();\n\n return modal;\n }\n}\n"],"names":["Selectors","GradebookEditTreeBulkMove","BulkAction","constructor","courseId","getBulkActionTriggerSelector","modal","this","showModal","registerCustomListenerEvents","showInDropdown","Templates","render","showindropdown","getBody","getRoot","on","ModalEvents","shown","moveOptionsTree","MoveOptionsTree","setButtonDisabled","hidden","destroy","save","selectedMoveOption","document","querySelector","value","dataset","id","submit","fetchGradeTree","request","methodname","args","courseid","Ajax","call","gradeTree","JSON","parse","ModalSaveCancel","create","title","body","renderModalBody","buttons","large","show"],"mappings":"i9BAgCMA,uBACY,iBADZA,wBAEa,yBAFbA,6BAGkB,gCAGHC,kCAAkCC,qBAiBnDC,YAAYC,kDAdD,6CAGO,uCAGN,WAUHA,SAAWA,SAQpBC,qCACW,iFAUDC,YAAcC,KAAKC,iBACpBC,6BAA6BH,qCAURI,uBACnBC,mBAAUC,OAAO,sDAAuD,CAC3EC,eAAgBH,oDAWWJ,aACzBA,MAAMQ,UAEZR,MAAMS,UAAUC,GAAGC,sBAAYC,OAAO,UAC7BC,gBAAkB,IAAIC,4BAAgB,KAEvCd,MAAMe,kBAAkB,QAAQ,SAIxCf,MAAMS,UAAUC,GAAGC,sBAAYK,QAAQ,KACnChB,MAAMiB,aAGVjB,MAAMS,UAAUC,GAAGC,sBAAYO,MAAM,KAE7BjB,KAAKY,iBAAmBZ,KAAKY,gBAAgBM,qBAE7CC,SAASC,cAAc3B,yBAAyB4B,MAAQ,EACxDF,SAASC,cAAc3B,8BAA8B4B,MAAQrB,KAAKY,gBAAgBM,mBAAmBI,QAAQC,GAE7GJ,SAASC,cAAc3B,wBAAwB+B,aAW3DC,uBACUC,QAAU,CACZC,WAAY,6BACZC,KAAM,CACFC,SAAU7B,KAAKH,kBAGhBiC,cAAKC,KAAK,CAACL,UAAU,kCAWL,OAAnB1B,KAAKgC,iBACAA,gBAAkBhC,KAAKyB,kBAGzBrB,mBAAUC,OAAO,yDACpB4B,KAAKC,MAAMlC,KAAKgC,oCAUdjC,YAAcoC,2BAAgBC,OAAO,CACvCC,YAAa,mBAAU,aAAc,UACrCC,WAAYtC,KAAKuC,kBACjBC,QAAS,CACLvB,WAAY,mBAAU,SAE1BwB,OAAO,WAGX1C,MAAMe,kBAAkB,QAAQ,GAChCf,MAAM2C,OAEC3C"} \ No newline at end of file +{"version":3,"file":"move.min.js","sources":["../../../../src/bulkactions/edit/tree/move.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 * Class that defines the bulk move action in the gradebook setup page.\n *\n * @module core_grades/bulkactions/edit/tree/move\n * @copyright 2023 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport {get_string as getString} from 'core/str';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport Templates from 'core/templates';\nimport Ajax from 'core/ajax';\nimport ModalEvents from 'core/modal_events';\nimport MoveOptionsTree from 'core_grades/bulkactions/edit/tree/move_options_tree';\n\n/** @constant {Object} The object containing the relevant selectors. */\nconst Selectors = {\n editTreeForm: '#gradetreeform',\n bulkMoveInput: 'input[name=\"bulkmove\"]',\n bulkMoveAfterInput: 'input[name=\"moveafter\"]'\n};\n\nexport default class GradebookEditTreeBulkMove extends BulkAction {\n\n /** @property {int|null} courseId The course ID. */\n courseId = null;\n\n /** @property {MoveOptionsTree|null} moveOptionsTree The move options tree object. */\n moveOptionsTree = null;\n\n /** @property {string|null} gradeTree The grade tree structure. */\n gradeTree = null;\n\n /**\n * The class constructor.\n *\n * @param {int} courseId The course ID.\n * @returns {void}\n */\n constructor(courseId) {\n super();\n this.courseId = courseId;\n }\n\n /**\n * Defines the selector of the element that triggers the bulk move action.\n *\n * @returns {string} The bulk move action trigger selector.\n */\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"move\"]';\n }\n\n /**\n * Defines the behavior once the bulk move action is triggered.\n *\n * @method executeBulkAction\n * @returns {void}\n */\n async triggerBulkAction() {\n const modal = await this.showModal();\n this.registerCustomListenerEvents(modal);\n }\n\n /**\n * Renders the bulk move action trigger element.\n *\n * @method renderBulkActionTrigger\n * @param {boolean} showInDropdown Whether the action is displayed under a 'More' dropdown or as a separate button.\n * @param {number} index The index of the action.\n * @returns {Promise} The bulk move action trigger promise\n */\n async renderBulkActionTrigger(showInDropdown, index) {\n return Templates.render('core_grades/bulkactions/edit/tree/bulk_move_trigger', {\n showindropdown: showInDropdown,\n isfirst: index === 0,\n });\n }\n\n /**\n * Register custom event listeners.\n *\n * @method registerCustomClickListenerEvents\n * @param {Object} modal The modal object.\n * @returns {void}\n */\n async registerCustomListenerEvents(modal) {\n await modal.getBody();\n // Initialize the move options tree once the modal is shown.\n modal.getRoot().on(ModalEvents.shown, () => {\n this.moveOptionsTree = new MoveOptionsTree(() => {\n // Enable the 'Move' action button once something is selected.\n modal.setButtonDisabled('save', false);\n });\n });\n // Destroy the modal once it is hidden.\n modal.getRoot().on(ModalEvents.hidden, () => {\n modal.destroy();\n });\n // Define the move action event.\n modal.getRoot().on(ModalEvents.save, () => {\n // Make sure that a move option is selected.\n if (this.moveOptionsTree && this.moveOptionsTree.selectedMoveOption) {\n // Set the relevant form values.\n document.querySelector(Selectors.bulkMoveInput).value = 1;\n document.querySelector(Selectors.bulkMoveAfterInput).value = this.moveOptionsTree.selectedMoveOption.dataset.id;\n // Submit the form.\n document.querySelector(Selectors.editTreeForm).submit();\n }\n });\n }\n\n /**\n * Fetch the grade tree structure for the current course.\n *\n * @method fetchGradeTree\n * @returns {Promise} The grade tree promise\n */\n fetchGradeTree() {\n const request = {\n methodname: 'core_grades_get_grade_tree',\n args: {\n courseid: this.courseId,\n },\n };\n return Ajax.call([request])[0];\n }\n\n /**\n * Renders the bulk move modal body.\n *\n * @method renderModalBody\n * @returns {Promise} The modal body promise\n */\n async renderModalBody() {\n // We need to fetch the grade tree structure only once.\n if (this.gradeTree === null) {\n this.gradeTree = await this.fetchGradeTree();\n }\n\n return Templates.render('core_grades/bulkactions/edit/tree/bulk_move_grade_tree',\n JSON.parse(this.gradeTree));\n }\n\n /**\n * Show the bulk move modal.\n *\n * @method showModal\n * @returns {Promise} The modal promise\n */\n async showModal() {\n const modal = await ModalSaveCancel.create({\n title: await getString('movesitems', 'grades'),\n body: await this.renderModalBody(),\n buttons: {\n save: await getString('move')\n },\n large: true,\n });\n // Disable the 'Move' action button until something is selected.\n modal.setButtonDisabled('save', true);\n modal.show();\n\n return modal;\n }\n}\n"],"names":["Selectors","GradebookEditTreeBulkMove","BulkAction","constructor","courseId","getBulkActionTriggerSelector","modal","this","showModal","registerCustomListenerEvents","showInDropdown","index","Templates","render","showindropdown","isfirst","getBody","getRoot","on","ModalEvents","shown","moveOptionsTree","MoveOptionsTree","setButtonDisabled","hidden","destroy","save","selectedMoveOption","document","querySelector","value","dataset","id","submit","fetchGradeTree","request","methodname","args","courseid","Ajax","call","gradeTree","JSON","parse","ModalSaveCancel","create","title","body","renderModalBody","buttons","large","show"],"mappings":"i9BAgCMA,uBACY,iBADZA,wBAEa,yBAFbA,6BAGkB,gCAGHC,kCAAkCC,qBAiBnDC,YAAYC,kDAdD,6CAGO,uCAGN,WAUHA,SAAWA,SAQpBC,qCACW,iFAUDC,YAAcC,KAAKC,iBACpBC,6BAA6BH,qCAWRI,eAAgBC,cACnCC,mBAAUC,OAAO,sDAAuD,CAC3EC,eAAgBJ,eAChBK,QAAmB,IAAVJ,2CAWkBL,aACzBA,MAAMU,UAEZV,MAAMW,UAAUC,GAAGC,sBAAYC,OAAO,UAC7BC,gBAAkB,IAAIC,4BAAgB,KAEvChB,MAAMiB,kBAAkB,QAAQ,SAIxCjB,MAAMW,UAAUC,GAAGC,sBAAYK,QAAQ,KACnClB,MAAMmB,aAGVnB,MAAMW,UAAUC,GAAGC,sBAAYO,MAAM,KAE7BnB,KAAKc,iBAAmBd,KAAKc,gBAAgBM,qBAE7CC,SAASC,cAAc7B,yBAAyB8B,MAAQ,EACxDF,SAASC,cAAc7B,8BAA8B8B,MAAQvB,KAAKc,gBAAgBM,mBAAmBI,QAAQC,GAE7GJ,SAASC,cAAc7B,wBAAwBiC,aAW3DC,uBACUC,QAAU,CACZC,WAAY,6BACZC,KAAM,CACFC,SAAU/B,KAAKH,kBAGhBmC,cAAKC,KAAK,CAACL,UAAU,kCAWL,OAAnB5B,KAAKkC,iBACAA,gBAAkBlC,KAAK2B,kBAGzBtB,mBAAUC,OAAO,yDACpB6B,KAAKC,MAAMpC,KAAKkC,oCAUdnC,YAAcsC,2BAAgBC,OAAO,CACvCC,YAAa,mBAAU,aAAc,UACrCC,WAAYxC,KAAKyC,kBACjBC,QAAS,CACLvB,WAAY,mBAAU,SAE1BwB,OAAO,WAGX5C,MAAMiB,kBAAkB,QAAQ,GAChCjB,MAAM6C,OAEC7C"} \ No newline at end of file diff --git a/grade/amd/src/bulkactions/edit/tree/move.js b/grade/amd/src/bulkactions/edit/tree/move.js index 43af4789dda..b274e60a502 100644 --- a/grade/amd/src/bulkactions/edit/tree/move.js +++ b/grade/amd/src/bulkactions/edit/tree/move.js @@ -83,11 +83,13 @@ export default class GradebookEditTreeBulkMove extends BulkAction { * * @method renderBulkActionTrigger * @param {boolean} showInDropdown Whether the action is displayed under a 'More' dropdown or as a separate button. + * @param {number} index The index of the action. * @returns {Promise} The bulk move action trigger promise */ - async renderBulkActionTrigger(showInDropdown) { + async renderBulkActionTrigger(showInDropdown, index) { return Templates.render('core_grades/bulkactions/edit/tree/bulk_move_trigger', { showindropdown: showInDropdown, + isfirst: index === 0, }); } diff --git a/lib/amd/build/bulkactions/bulk_action.min.js b/lib/amd/build/bulkactions/bulk_action.min.js index 72c2c0fc577..00e918c390d 100644 --- a/lib/amd/build/bulkactions/bulk_action.min.js +++ b/lib/amd/build/bulkactions/bulk_action.min.js @@ -6,6 +6,6 @@ define("core/bulkactions/bulk_action",["exports"],(function(_exports){Object.def * @copyright 2023 Mihail Geshoski * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class{constructor(){var obj,key,value;value=[],(key="selectedItems")in(obj=this)?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}registerListenerEvents(containerElement){containerElement.addEventListener("click",(e=>{e.target.closest(this.getBulkActionTriggerSelector())&&(e.preventDefault(),this.triggerBulkAction())}))}setSelectedItems(selectedItems){this.selectedItems=selectedItems}getBulkActionTriggerSelector(){throw new Error("getBulkActionTriggerSelector() must be implemented in ".concat(this.constructor.name))}triggerBulkAction(){throw new Error("triggerBulkAction() must be implemented in ".concat(this.constructor.name))}renderBulkActionTrigger(){throw new Error("renderBulkActionTrigger(".concat(arguments.length>0&&void 0!==arguments[0]&&arguments[0],") must be implemented in ").concat(this.constructor.name))}},_exports.default})); +class{constructor(){var obj,key,value;value=[],(key="selectedItems")in(obj=this)?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}registerListenerEvents(containerElement){containerElement.addEventListener("click",(e=>{e.target.closest(this.getBulkActionTriggerSelector())&&(e.preventDefault(),this.triggerBulkAction())}))}setSelectedItems(selectedItems){this.selectedItems=selectedItems}getBulkActionTriggerSelector(){throw new Error("getBulkActionTriggerSelector() must be implemented in ".concat(this.constructor.name))}triggerBulkAction(){throw new Error("triggerBulkAction() must be implemented in ".concat(this.constructor.name))}renderBulkActionTrigger(){let index=arguments.length>1?arguments[1]:void 0;throw new Error("renderBulkActionTrigger(".concat(arguments.length>0&&void 0!==arguments[0]&&arguments[0],", ").concat(index,") must be implemented in ").concat(this.constructor.name))}},_exports.default})); //# sourceMappingURL=bulk_action.min.js.map \ No newline at end of file diff --git a/lib/amd/build/bulkactions/bulk_action.min.js.map b/lib/amd/build/bulkactions/bulk_action.min.js.map index 85e5c2d4028..b30b1c50f6c 100644 --- a/lib/amd/build/bulkactions/bulk_action.min.js.map +++ b/lib/amd/build/bulkactions/bulk_action.min.js.map @@ -1 +1 @@ -{"version":3,"file":"bulk_action.min.js","sources":["../../src/bulkactions/bulk_action.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 * Base class for defining a bulk action.\n *\n * @module core/bulkactions/bulk_action\n * @copyright 2023 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default class BulkAction {\n\n /** @property {array} selectedItems The array of selected item elements. */\n selectedItems = [];\n\n /**\n * Registers the listener events for the bulk actions.\n *\n * @method registerListenerEvents\n * @param {HTMLElement} containerElement The container element for the bulk actions.\n * @returns {void}\n */\n registerListenerEvents(containerElement) {\n // Listen for the click event on the bulk action trigger element.\n containerElement.addEventListener('click', (e) => {\n if (e.target.closest(this.getBulkActionTriggerSelector())) {\n e.preventDefault();\n this.triggerBulkAction();\n }\n });\n }\n\n /**\n * Setter method for the selectedItems property.\n *\n * @method setSelectedItems\n * @param {Array} selectedItems The array of selected item elements..\n * @returns {void}\n */\n setSelectedItems(selectedItems) {\n this.selectedItems = selectedItems;\n }\n\n /**\n * Defines the selector of the element that triggers the bulk action.\n *\n * @method getBulkActionTriggerSelector\n * @returns {string}\n */\n getBulkActionTriggerSelector() {\n throw new Error(`getBulkActionTriggerSelector() must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Defines the behavior once the bulk action is triggered.\n *\n * @method triggerBulkAction\n */\n triggerBulkAction() {\n throw new Error(`triggerBulkAction() must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Renders the bulk action trigger element.\n *\n * @method renderBulkActionTrigger\n * @param {boolean} showInDropdown Whether the action is displayed under a 'More' dropdown or as a separate button.\n * @returns {Promise}\n */\n renderBulkActionTrigger(showInDropdown = false) {\n throw new Error(`renderBulkActionTrigger(${showInDropdown}) must be implemented in ${this.constructor.name}`);\n }\n}\n"],"names":["registerListenerEvents","containerElement","addEventListener","e","target","closest","this","getBulkActionTriggerSelector","preventDefault","triggerBulkAction","setSelectedItems","selectedItems","Error","constructor","name","renderBulkActionTrigger"],"mappings":";;;;;;;;4CA0BoB,2IAShBA,uBAAuBC,kBAEnBA,iBAAiBC,iBAAiB,SAAUC,IACpCA,EAAEC,OAAOC,QAAQC,KAAKC,kCACtBJ,EAAEK,sBACGC,wBAYjBC,iBAAiBC,oBACRA,cAAgBA,cASzBJ,qCACU,IAAIK,sEAA+DN,KAAKO,YAAYC,OAQ9FL,0BACU,IAAIG,2DAAoDN,KAAKO,YAAYC,OAUnFC,gCACU,IAAIH,oIAA2EN,KAAKO,YAAYC"} \ No newline at end of file +{"version":3,"file":"bulk_action.min.js","sources":["../../src/bulkactions/bulk_action.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 * Base class for defining a bulk action.\n *\n * @module core/bulkactions/bulk_action\n * @copyright 2023 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default class BulkAction {\n\n /** @property {array} selectedItems The array of selected item elements. */\n selectedItems = [];\n\n /**\n * Registers the listener events for the bulk actions.\n *\n * @method registerListenerEvents\n * @param {HTMLElement} containerElement The container element for the bulk actions.\n * @returns {void}\n */\n registerListenerEvents(containerElement) {\n // Listen for the click event on the bulk action trigger element.\n containerElement.addEventListener('click', (e) => {\n if (e.target.closest(this.getBulkActionTriggerSelector())) {\n e.preventDefault();\n this.triggerBulkAction();\n }\n });\n }\n\n /**\n * Setter method for the selectedItems property.\n *\n * @method setSelectedItems\n * @param {Array} selectedItems The array of selected item elements..\n * @returns {void}\n */\n setSelectedItems(selectedItems) {\n this.selectedItems = selectedItems;\n }\n\n /**\n * Defines the selector of the element that triggers the bulk action.\n *\n * @method getBulkActionTriggerSelector\n * @returns {string}\n */\n getBulkActionTriggerSelector() {\n throw new Error(`getBulkActionTriggerSelector() must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Defines the behavior once the bulk action is triggered.\n *\n * @method triggerBulkAction\n */\n triggerBulkAction() {\n throw new Error(`triggerBulkAction() must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Renders the bulk action trigger element.\n *\n * @method renderBulkActionTrigger\n * @param {boolean} showInDropdown Whether the action is displayed under a 'More' dropdown or as a separate button.\n * @param {number} index The index of the action.\n * @returns {Promise}\n */\n renderBulkActionTrigger(showInDropdown = false, index) {\n throw new Error(`renderBulkActionTrigger(${showInDropdown}, ${index}) must be implemented in ${this.constructor.name}`);\n }\n}\n"],"names":["registerListenerEvents","containerElement","addEventListener","e","target","closest","this","getBulkActionTriggerSelector","preventDefault","triggerBulkAction","setSelectedItems","selectedItems","Error","constructor","name","renderBulkActionTrigger","index"],"mappings":";;;;;;;;4CA0BoB,2IAShBA,uBAAuBC,kBAEnBA,iBAAiBC,iBAAiB,SAAUC,IACpCA,EAAEC,OAAOC,QAAQC,KAAKC,kCACtBJ,EAAEK,sBACGC,wBAYjBC,iBAAiBC,oBACRA,cAAgBA,cASzBJ,qCACU,IAAIK,sEAA+DN,KAAKO,YAAYC,OAQ9FL,0BACU,IAAIG,2DAAoDN,KAAKO,YAAYC,OAWnFC,8BAAgDC,mDACtC,IAAIJ,6GAAoDI,0CAAiCV,KAAKO,YAAYC"} \ No newline at end of file diff --git a/lib/amd/build/bulkactions/bulk_actions.min.js b/lib/amd/build/bulkactions/bulk_actions.min.js index f533d923622..e657e401348 100644 --- a/lib/amd/build/bulkactions/bulk_actions.min.js +++ b/lib/amd/build/bulkactions/bulk_actions.min.js @@ -5,6 +5,6 @@ define("core/bulkactions/bulk_actions",["exports","core/templates","core/str","c * @module core/bulkactions/bulk_actions * @copyright 2023 Mihail Geshoski * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};const Selectors_stickyFooterContainer="#sticky-footer",Selectors_selectedItemsCountContainer='[data-type="bulkactions"] [data-for="bulkcount"]',Selectors_cancelBulkActionModeElement='[data-type="bulkactions"] [data-action="bulkcancel"]',Selectors_bulkModeContainer='[data-type="bulkactions"]',Selectors_bulkActionsContainer='[data-type="bulkactions"] [data-for="bulktools"]';return _exports.default=class{constructor(){let maxButtons=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(_defineProperty(this,"initialStickyFooterContent",null),_defineProperty(this,"selectedItems",[]),_defineProperty(this,"isBulkActionsModeEnabled",!1),_defineProperty(this,"maxButtons",5),!this.getStickyFooterContainer())throw new Error("Sticky footer not found.");this.initialStickyFooterContent=this.getStickyFooterContainer().innerHTML,maxButtons&&(this.maxButtons=maxButtons),this.registerItemSelectChangeEvent((async()=>{this.selectedItems=this.getSelectedItems(),this.selectedItems.length>0?this.isBulkActionsModeEnabled?await this.updateBulkItemSelection():await this.enableBulkActionsMode():this.disableBulkActionsMode()}))}getBulkActions(){throw new Error("getBulkActions() must be implemented in ".concat(this.constructor.name))}getSelectedItems(){throw new Error("getSelectedItems() must be implemented in ".concat(this.constructor.name))}registerItemSelectChangeEvent(eventHandler){throw new Error("registerItemSelectChangeEvent(".concat(eventHandler,") must be implemented in ").concat(this.constructor.name))}getStickyFooterContainer(){return document.querySelector(Selectors_stickyFooterContainer)}async enableBulkActionsMode(){(0,_stickyFooter.enableStickyFooter)(),this.getStickyFooterContainer().innerHTML=await this.renderBulkActions();const bulkModeContainer=this.getStickyFooterContainer().querySelector(Selectors_bulkModeContainer),bulkActionsContainer=bulkModeContainer.querySelector(Selectors_bulkActionsContainer);this.getBulkActions().forEach((bulkAction=>{bulkAction.registerListenerEvents(bulkActionsContainer),bulkAction.setSelectedItems(this.selectedItems)})),bulkModeContainer.addEventListener("click",(e=>{e.target.closest(Selectors_cancelBulkActionModeElement)&&(this.selectedItems.forEach((item=>{item.checked=!1})),this.disableBulkActionsMode())})),this.isBulkActionsModeEnabled=!0}disableBulkActionsMode(){this.initialStickyFooterContent.length>0?this.getStickyFooterContainer().innerHTML=this.initialStickyFooterContent:(0,_stickyFooter.disableStickyFooter)(),this.isBulkActionsModeEnabled=!1}async renderBulkActions(){const data={bulkselectioncount:this.selectedItems.length,actions:[],moreactions:[],hasmoreactions:!1},bulkActions=this.getBulkActions(),showMoreButton=bulkActions.length>this.maxButtons;return(await Promise.all(bulkActions.map(((bulkAction,index)=>bulkAction.renderBulkActionTrigger(showMoreButton&&index>=this.maxButtons-1))))).forEach(((actionTrigger,index)=>{showMoreButton&&index>=this.maxButtons-1?data.moreactions.push({actiontrigger:actionTrigger}):data.actions.push({actiontrigger:actionTrigger})})),data.hasmoreactions=data.moreactions.length>0,_templates.default.render("core/bulkactions/bulk_actions",data)}async updateBulkItemSelection(){const bulkSelection=await(0,_str.get_string)("bulkselection","core",this.selectedItems.length);document.querySelector(Selectors_selectedItemsCountContainer).innerHTML=bulkSelection}},_exports.default})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};const Selectors_stickyFooterContainer="#sticky-footer",Selectors_selectedItemsCountContainer='[data-type="bulkactions"] [data-for="bulkcount"]',Selectors_cancelBulkActionModeElement='[data-type="bulkactions"] [data-action="bulkcancel"]',Selectors_bulkModeContainer='[data-type="bulkactions"]',Selectors_bulkActionsContainer='[data-type="bulkactions"] [data-for="bulktools"]';return _exports.default=class{constructor(){let maxButtons=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(_defineProperty(this,"initialStickyFooterContent",null),_defineProperty(this,"selectedItems",[]),_defineProperty(this,"isBulkActionsModeEnabled",!1),_defineProperty(this,"maxButtons",5),!this.getStickyFooterContainer())throw new Error("Sticky footer not found.");this.initialStickyFooterContent=this.getStickyFooterContainer().innerHTML,maxButtons&&(this.maxButtons=maxButtons),this.registerItemSelectChangeEvent((async()=>{this.selectedItems=this.getSelectedItems(),this.selectedItems.length>0?this.isBulkActionsModeEnabled?await this.updateBulkItemSelection():await this.enableBulkActionsMode():this.disableBulkActionsMode()}))}getBulkActions(){throw new Error("getBulkActions() must be implemented in ".concat(this.constructor.name))}getSelectedItems(){throw new Error("getSelectedItems() must be implemented in ".concat(this.constructor.name))}registerItemSelectChangeEvent(eventHandler){throw new Error("registerItemSelectChangeEvent(".concat(eventHandler,") must be implemented in ").concat(this.constructor.name))}getStickyFooterContainer(){return document.querySelector(Selectors_stickyFooterContainer)}async enableBulkActionsMode(){(0,_stickyFooter.enableStickyFooter)(),this.getStickyFooterContainer().innerHTML=await this.renderBulkActions();const bulkModeContainer=this.getStickyFooterContainer().querySelector(Selectors_bulkModeContainer),bulkActionsContainer=bulkModeContainer.querySelector(Selectors_bulkActionsContainer);this.getBulkActions().forEach((bulkAction=>{bulkAction.registerListenerEvents(bulkActionsContainer),bulkAction.setSelectedItems(this.selectedItems)})),bulkModeContainer.addEventListener("click",(e=>{e.target.closest(Selectors_cancelBulkActionModeElement)&&(this.selectedItems.forEach((item=>{item.checked=!1})),this.disableBulkActionsMode())})),this.isBulkActionsModeEnabled=!0}disableBulkActionsMode(){this.initialStickyFooterContent.length>0?this.getStickyFooterContainer().innerHTML=this.initialStickyFooterContent:(0,_stickyFooter.disableStickyFooter)(),this.isBulkActionsModeEnabled=!1}async renderBulkActions(){const data={bulkselectioncount:this.selectedItems.length,actions:[],moreactions:[],hasmoreactions:!1},bulkActions=this.getBulkActions(),showMoreButton=bulkActions.length>this.maxButtons;return(await Promise.all(bulkActions.map(((bulkAction,index)=>bulkAction.renderBulkActionTrigger(showMoreButton&&index>=this.maxButtons-1,index))))).forEach(((actionTrigger,index)=>{showMoreButton&&index>=this.maxButtons-1?data.moreactions.push({actiontrigger:actionTrigger}):data.actions.push({actiontrigger:actionTrigger})})),data.hasmoreactions=data.moreactions.length>0,_templates.default.render("core/bulkactions/bulk_actions",data)}async updateBulkItemSelection(){const bulkSelection=await(0,_str.get_string)("bulkselection","core",this.selectedItems.length);document.querySelector(Selectors_selectedItemsCountContainer).innerHTML=bulkSelection}},_exports.default})); //# sourceMappingURL=bulk_actions.min.js.map \ No newline at end of file diff --git a/lib/amd/build/bulkactions/bulk_actions.min.js.map b/lib/amd/build/bulkactions/bulk_actions.min.js.map index b27b8576fb2..2cf06364a84 100644 --- a/lib/amd/build/bulkactions/bulk_actions.min.js.map +++ b/lib/amd/build/bulkactions/bulk_actions.min.js.map @@ -1 +1 @@ -{"version":3,"file":"bulk_actions.min.js","sources":["../../src/bulkactions/bulk_actions.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\nimport Templates from 'core/templates';\nimport {get_string as getString} from 'core/str';\nimport {disableStickyFooter, enableStickyFooter} from 'core/sticky-footer';\n\n/**\n * Base class for defining a bulk actions area within a page.\n *\n * @module core/bulkactions/bulk_actions\n * @copyright 2023 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/** @constant {Object} The object containing the relevant selectors. */\nconst Selectors = {\n stickyFooterContainer: '#sticky-footer',\n selectedItemsCountContainer: '[data-type=\"bulkactions\"] [data-for=\"bulkcount\"]',\n cancelBulkActionModeElement: '[data-type=\"bulkactions\"] [data-action=\"bulkcancel\"]',\n bulkModeContainer: '[data-type=\"bulkactions\"]',\n bulkActionsContainer: '[data-type=\"bulkactions\"] [data-for=\"bulktools\"]'\n};\n\nexport default class BulkActions {\n\n /** @property {string|null} initialStickyFooterContent The initial content of the sticky footer. */\n initialStickyFooterContent = null;\n\n /** @property {Array} selectedItems The array of selected item elements. */\n selectedItems = [];\n\n /** @property {boolean} isBulkActionsModeEnabled Whether the bulk actions mode is enabled. */\n isBulkActionsModeEnabled = false;\n\n /**\n * @property {int} maxButtons Sets the maximum number of action buttons to display. If exceeded, additional actions\n * are shown in a dropdown menu.\n */\n maxButtons = 5;\n\n /**\n * The class constructor.\n *\n * @param {int|null} maxButtons Sets the maximum number of action buttons to display. If exceeded, additional actions\n * are shown in a dropdown menu.\n * @returns {void}\n */\n constructor(maxButtons = null) {\n if (!this.getStickyFooterContainer()) {\n throw new Error('Sticky footer not found.');\n }\n // Store any pre-existing content in the sticky footer. When bulk actions mode is enabled, this content will be\n // replaced with the bulk actions content and restored when bulk actions mode is disabled.\n this.initialStickyFooterContent = this.getStickyFooterContainer().innerHTML;\n if (maxButtons) {\n this.maxButtons = maxButtons;\n }\n // Register and handle the item select change event.\n this.registerItemSelectChangeEvent(async() => {\n this.selectedItems = this.getSelectedItems();\n if (this.selectedItems.length > 0) { // At least one item is selected.\n // If the bulk actions mode is already enabled only update the selected items count.\n if (this.isBulkActionsModeEnabled) {\n await this.updateBulkItemSelection();\n } else { // Otherwise, enable the bulk action mode.\n await this.enableBulkActionsMode();\n }\n } else { // No items are selected, disable the bulk action mode.\n this.disableBulkActionsMode();\n }\n });\n }\n\n /**\n * Returns the array of the relevant bulk action objects.\n *\n * @method getBulkActions\n * @returns {Array}\n */\n getBulkActions() {\n throw new Error(`getBulkActions() must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Returns the array of selected items.\n *\n * @method getSelectedItems\n * @returns {Array}\n */\n getSelectedItems() {\n throw new Error(`getSelectedItems() must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Adds the listener for the item select change event.\n * The event handler function that is passed as a parameter should be called right after the event is triggered.\n *\n * @method registerItemSelectChangeEvent\n * @param {function} eventHandler The event handler function.\n * @returns {void}\n */\n registerItemSelectChangeEvent(eventHandler) {\n throw new Error(`registerItemSelectChangeEvent(${eventHandler}) must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Returns the sticky footer container.\n *\n * @method getStickyFooterContainer\n * @returns {HTMLElement}\n */\n getStickyFooterContainer() {\n return document.querySelector(Selectors.stickyFooterContainer);\n }\n\n /**\n * Enables the bulk action mode.\n *\n * @method enableBulkActionsMode\n * @returns {Promise}\n */\n async enableBulkActionsMode() {\n // Make sure that the sticky footer is enabled.\n enableStickyFooter();\n // Render the bulk actions content in the sticky footer container.\n this.getStickyFooterContainer().innerHTML = await this.renderBulkActions();\n const bulkModeContainer = this.getStickyFooterContainer().querySelector(Selectors.bulkModeContainer);\n const bulkActionsContainer = bulkModeContainer.querySelector(Selectors.bulkActionsContainer);\n this.getBulkActions().forEach((bulkAction) => {\n // Register the listener events for each available bulk action.\n bulkAction.registerListenerEvents(bulkActionsContainer);\n // Set the selected items for each available bulk action.\n bulkAction.setSelectedItems(this.selectedItems);\n });\n // Register the click listener event for the cancel bulk mode button.\n bulkModeContainer.addEventListener('click', (e) => {\n if (e.target.closest(Selectors.cancelBulkActionModeElement)) {\n // Uncheck all selected items.\n this.selectedItems.forEach((item) => {\n item.checked = false;\n });\n // Disable the bulk action mode.\n this.disableBulkActionsMode();\n }\n });\n this.isBulkActionsModeEnabled = true;\n }\n\n /**\n * Disables the bulk action mode.\n *\n * @method disableBulkActionsMode\n * @returns {void}\n */\n disableBulkActionsMode() {\n // If there was any previous (initial) content in the sticky footer, restore it.\n if (this.initialStickyFooterContent.length > 0) {\n this.getStickyFooterContainer().innerHTML = this.initialStickyFooterContent;\n } else { // No previous content to restore, disable the sticky footer.\n disableStickyFooter();\n }\n this.isBulkActionsModeEnabled = false;\n }\n\n /**\n * Renders the bulk actions content.\n *\n * @method renderBulkActions\n * @returns {Promise}\n */\n async renderBulkActions() {\n const data = {\n bulkselectioncount: this.selectedItems.length,\n actions: [],\n moreactions: [],\n hasmoreactions: false,\n };\n const bulkActions = this.getBulkActions();\n const showMoreButton = bulkActions.length > this.maxButtons;\n\n // Get all bulk actions and render them in order.\n const actions = await Promise.all(\n bulkActions.map((bulkAction, index) =>\n bulkAction.renderBulkActionTrigger(showMoreButton && (index >= this.maxButtons - 1)))\n );\n\n // Separate rendered actions into data.actions and data.moreactions in the correct order.\n actions.forEach((actionTrigger, index) => {\n if (showMoreButton && (index >= this.maxButtons - 1)) {\n data.moreactions.push({'actiontrigger': actionTrigger});\n } else {\n data.actions.push({'actiontrigger': actionTrigger});\n }\n });\n\n data.hasmoreactions = data.moreactions.length > 0;\n\n return Templates.render('core/bulkactions/bulk_actions', data);\n }\n\n /**\n * Updates the selected items count in the bulk actions content.\n *\n * @method updateBulkItemSelection\n * @returns {void}\n */\n async updateBulkItemSelection() {\n const bulkSelection = await getString('bulkselection', 'core', this.selectedItems.length);\n document.querySelector(Selectors.selectedItemsCountContainer).innerHTML = bulkSelection;\n }\n}\n"],"names":["Selectors","constructor","maxButtons","this","getStickyFooterContainer","Error","initialStickyFooterContent","innerHTML","registerItemSelectChangeEvent","async","selectedItems","getSelectedItems","length","isBulkActionsModeEnabled","updateBulkItemSelection","enableBulkActionsMode","disableBulkActionsMode","getBulkActions","name","eventHandler","document","querySelector","renderBulkActions","bulkModeContainer","bulkActionsContainer","forEach","bulkAction","registerListenerEvents","setSelectedItems","addEventListener","e","target","closest","item","checked","data","bulkselectioncount","actions","moreactions","hasmoreactions","bulkActions","showMoreButton","Promise","all","map","index","renderBulkActionTrigger","actionTrigger","push","Templates","render","bulkSelection"],"mappings":";;;;;;;yJA4BMA,gCACqB,iBADrBA,sCAE2B,mDAF3BA,sCAG2B,uDAH3BA,4BAIiB,4BAJjBA,+BAKoB,iFA2BtBC,kBAAYC,kEAAa,0DArBI,2CAGb,qDAGW,qCAMd,IAUJC,KAAKC,iCACA,IAAIC,MAAM,iCAIfC,2BAA6BH,KAAKC,2BAA2BG,UAC9DL,kBACKA,WAAaA,iBAGjBM,+BAA8BC,eAC1BC,cAAgBP,KAAKQ,mBACtBR,KAAKO,cAAcE,OAAS,EAExBT,KAAKU,+BACCV,KAAKW,gCAELX,KAAKY,6BAGVC,4BAWjBC,uBACU,IAAIZ,wDAAiDF,KAAKF,YAAYiB,OAShFP,yBACU,IAAIN,0DAAmDF,KAAKF,YAAYiB,OAWlFV,8BAA8BW,oBACpB,IAAId,8CAAuCc,iDAAwChB,KAAKF,YAAYiB,OAS9Gd,kCACWgB,SAASC,cAAcrB,2GAazBI,2BAA2BG,gBAAkBJ,KAAKmB,0BACjDC,kBAAoBpB,KAAKC,2BAA2BiB,cAAcrB,6BAClEwB,qBAAuBD,kBAAkBF,cAAcrB,qCACxDiB,iBAAiBQ,SAASC,aAE3BA,WAAWC,uBAAuBH,sBAElCE,WAAWE,iBAAiBzB,KAAKO,kBAGrCa,kBAAkBM,iBAAiB,SAAUC,IACrCA,EAAEC,OAAOC,QAAQhC,8CAEZU,cAAce,SAASQ,OACxBA,KAAKC,SAAU,UAGdlB,kCAGRH,0BAA2B,EASpCG,yBAEQb,KAAKG,2BAA2BM,OAAS,OACpCR,2BAA2BG,UAAYJ,KAAKG,wEAIhDO,0BAA2B,kCAU1BsB,KAAO,CACTC,mBAAoBjC,KAAKO,cAAcE,OACvCyB,QAAS,GACTC,YAAa,GACbC,gBAAgB,GAEdC,YAAcrC,KAAKc,iBACnBwB,eAAiBD,YAAY5B,OAAST,KAAKD,wBAG3BwC,QAAQC,IAC1BH,YAAYI,KAAI,CAAClB,WAAYmB,QACzBnB,WAAWoB,wBAAwBL,gBAAmBI,OAAS1C,KAAKD,WAAa,OAIjFuB,SAAQ,CAACsB,cAAeF,SACxBJ,gBAAmBI,OAAS1C,KAAKD,WAAa,EAC9CiC,KAAKG,YAAYU,KAAK,eAAkBD,gBAExCZ,KAAKE,QAAQW,KAAK,eAAkBD,mBAI5CZ,KAAKI,eAAiBJ,KAAKG,YAAY1B,OAAS,EAEzCqC,mBAAUC,OAAO,gCAAiCf,4CAUnDgB,oBAAsB,mBAAU,gBAAiB,OAAQhD,KAAKO,cAAcE,QAClFQ,SAASC,cAAcrB,uCAAuCO,UAAY4C"} \ No newline at end of file +{"version":3,"file":"bulk_actions.min.js","sources":["../../src/bulkactions/bulk_actions.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\nimport Templates from 'core/templates';\nimport {get_string as getString} from 'core/str';\nimport {disableStickyFooter, enableStickyFooter} from 'core/sticky-footer';\n\n/**\n * Base class for defining a bulk actions area within a page.\n *\n * @module core/bulkactions/bulk_actions\n * @copyright 2023 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/** @constant {Object} The object containing the relevant selectors. */\nconst Selectors = {\n stickyFooterContainer: '#sticky-footer',\n selectedItemsCountContainer: '[data-type=\"bulkactions\"] [data-for=\"bulkcount\"]',\n cancelBulkActionModeElement: '[data-type=\"bulkactions\"] [data-action=\"bulkcancel\"]',\n bulkModeContainer: '[data-type=\"bulkactions\"]',\n bulkActionsContainer: '[data-type=\"bulkactions\"] [data-for=\"bulktools\"]'\n};\n\nexport default class BulkActions {\n\n /** @property {string|null} initialStickyFooterContent The initial content of the sticky footer. */\n initialStickyFooterContent = null;\n\n /** @property {Array} selectedItems The array of selected item elements. */\n selectedItems = [];\n\n /** @property {boolean} isBulkActionsModeEnabled Whether the bulk actions mode is enabled. */\n isBulkActionsModeEnabled = false;\n\n /**\n * @property {int} maxButtons Sets the maximum number of action buttons to display. If exceeded, additional actions\n * are shown in a dropdown menu.\n */\n maxButtons = 5;\n\n /**\n * The class constructor.\n *\n * @param {int|null} maxButtons Sets the maximum number of action buttons to display. If exceeded, additional actions\n * are shown in a dropdown menu.\n * @returns {void}\n */\n constructor(maxButtons = null) {\n if (!this.getStickyFooterContainer()) {\n throw new Error('Sticky footer not found.');\n }\n // Store any pre-existing content in the sticky footer. When bulk actions mode is enabled, this content will be\n // replaced with the bulk actions content and restored when bulk actions mode is disabled.\n this.initialStickyFooterContent = this.getStickyFooterContainer().innerHTML;\n if (maxButtons) {\n this.maxButtons = maxButtons;\n }\n // Register and handle the item select change event.\n this.registerItemSelectChangeEvent(async() => {\n this.selectedItems = this.getSelectedItems();\n if (this.selectedItems.length > 0) { // At least one item is selected.\n // If the bulk actions mode is already enabled only update the selected items count.\n if (this.isBulkActionsModeEnabled) {\n await this.updateBulkItemSelection();\n } else { // Otherwise, enable the bulk action mode.\n await this.enableBulkActionsMode();\n }\n } else { // No items are selected, disable the bulk action mode.\n this.disableBulkActionsMode();\n }\n });\n }\n\n /**\n * Returns the array of the relevant bulk action objects.\n *\n * @method getBulkActions\n * @returns {Array}\n */\n getBulkActions() {\n throw new Error(`getBulkActions() must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Returns the array of selected items.\n *\n * @method getSelectedItems\n * @returns {Array}\n */\n getSelectedItems() {\n throw new Error(`getSelectedItems() must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Adds the listener for the item select change event.\n * The event handler function that is passed as a parameter should be called right after the event is triggered.\n *\n * @method registerItemSelectChangeEvent\n * @param {function} eventHandler The event handler function.\n * @returns {void}\n */\n registerItemSelectChangeEvent(eventHandler) {\n throw new Error(`registerItemSelectChangeEvent(${eventHandler}) must be implemented in ${this.constructor.name}`);\n }\n\n /**\n * Returns the sticky footer container.\n *\n * @method getStickyFooterContainer\n * @returns {HTMLElement}\n */\n getStickyFooterContainer() {\n return document.querySelector(Selectors.stickyFooterContainer);\n }\n\n /**\n * Enables the bulk action mode.\n *\n * @method enableBulkActionsMode\n * @returns {Promise}\n */\n async enableBulkActionsMode() {\n // Make sure that the sticky footer is enabled.\n enableStickyFooter();\n // Render the bulk actions content in the sticky footer container.\n this.getStickyFooterContainer().innerHTML = await this.renderBulkActions();\n const bulkModeContainer = this.getStickyFooterContainer().querySelector(Selectors.bulkModeContainer);\n const bulkActionsContainer = bulkModeContainer.querySelector(Selectors.bulkActionsContainer);\n this.getBulkActions().forEach((bulkAction) => {\n // Register the listener events for each available bulk action.\n bulkAction.registerListenerEvents(bulkActionsContainer);\n // Set the selected items for each available bulk action.\n bulkAction.setSelectedItems(this.selectedItems);\n });\n // Register the click listener event for the cancel bulk mode button.\n bulkModeContainer.addEventListener('click', (e) => {\n if (e.target.closest(Selectors.cancelBulkActionModeElement)) {\n // Uncheck all selected items.\n this.selectedItems.forEach((item) => {\n item.checked = false;\n });\n // Disable the bulk action mode.\n this.disableBulkActionsMode();\n }\n });\n this.isBulkActionsModeEnabled = true;\n }\n\n /**\n * Disables the bulk action mode.\n *\n * @method disableBulkActionsMode\n * @returns {void}\n */\n disableBulkActionsMode() {\n // If there was any previous (initial) content in the sticky footer, restore it.\n if (this.initialStickyFooterContent.length > 0) {\n this.getStickyFooterContainer().innerHTML = this.initialStickyFooterContent;\n } else { // No previous content to restore, disable the sticky footer.\n disableStickyFooter();\n }\n this.isBulkActionsModeEnabled = false;\n }\n\n /**\n * Renders the bulk actions content.\n *\n * @method renderBulkActions\n * @returns {Promise}\n */\n async renderBulkActions() {\n const data = {\n bulkselectioncount: this.selectedItems.length,\n actions: [],\n moreactions: [],\n hasmoreactions: false,\n };\n const bulkActions = this.getBulkActions();\n const showMoreButton = bulkActions.length > this.maxButtons;\n\n // Get all bulk actions and render them in order.\n const actions = await Promise.all(\n bulkActions.map((bulkAction, index) =>\n bulkAction.renderBulkActionTrigger(\n showMoreButton && (index >= this.maxButtons - 1),\n index\n )\n )\n );\n\n // Separate rendered actions into data.actions and data.moreactions in the correct order.\n actions.forEach((actionTrigger, index) => {\n if (showMoreButton && (index >= this.maxButtons - 1)) {\n data.moreactions.push({'actiontrigger': actionTrigger});\n } else {\n data.actions.push({'actiontrigger': actionTrigger});\n }\n });\n\n data.hasmoreactions = data.moreactions.length > 0;\n\n return Templates.render('core/bulkactions/bulk_actions', data);\n }\n\n /**\n * Updates the selected items count in the bulk actions content.\n *\n * @method updateBulkItemSelection\n * @returns {void}\n */\n async updateBulkItemSelection() {\n const bulkSelection = await getString('bulkselection', 'core', this.selectedItems.length);\n document.querySelector(Selectors.selectedItemsCountContainer).innerHTML = bulkSelection;\n }\n}\n"],"names":["Selectors","constructor","maxButtons","this","getStickyFooterContainer","Error","initialStickyFooterContent","innerHTML","registerItemSelectChangeEvent","async","selectedItems","getSelectedItems","length","isBulkActionsModeEnabled","updateBulkItemSelection","enableBulkActionsMode","disableBulkActionsMode","getBulkActions","name","eventHandler","document","querySelector","renderBulkActions","bulkModeContainer","bulkActionsContainer","forEach","bulkAction","registerListenerEvents","setSelectedItems","addEventListener","e","target","closest","item","checked","data","bulkselectioncount","actions","moreactions","hasmoreactions","bulkActions","showMoreButton","Promise","all","map","index","renderBulkActionTrigger","actionTrigger","push","Templates","render","bulkSelection"],"mappings":";;;;;;;yJA4BMA,gCACqB,iBADrBA,sCAE2B,mDAF3BA,sCAG2B,uDAH3BA,4BAIiB,4BAJjBA,+BAKoB,iFA2BtBC,kBAAYC,kEAAa,0DArBI,2CAGb,qDAGW,qCAMd,IAUJC,KAAKC,iCACA,IAAIC,MAAM,iCAIfC,2BAA6BH,KAAKC,2BAA2BG,UAC9DL,kBACKA,WAAaA,iBAGjBM,+BAA8BC,eAC1BC,cAAgBP,KAAKQ,mBACtBR,KAAKO,cAAcE,OAAS,EAExBT,KAAKU,+BACCV,KAAKW,gCAELX,KAAKY,6BAGVC,4BAWjBC,uBACU,IAAIZ,wDAAiDF,KAAKF,YAAYiB,OAShFP,yBACU,IAAIN,0DAAmDF,KAAKF,YAAYiB,OAWlFV,8BAA8BW,oBACpB,IAAId,8CAAuCc,iDAAwChB,KAAKF,YAAYiB,OAS9Gd,kCACWgB,SAASC,cAAcrB,2GAazBI,2BAA2BG,gBAAkBJ,KAAKmB,0BACjDC,kBAAoBpB,KAAKC,2BAA2BiB,cAAcrB,6BAClEwB,qBAAuBD,kBAAkBF,cAAcrB,qCACxDiB,iBAAiBQ,SAASC,aAE3BA,WAAWC,uBAAuBH,sBAElCE,WAAWE,iBAAiBzB,KAAKO,kBAGrCa,kBAAkBM,iBAAiB,SAAUC,IACrCA,EAAEC,OAAOC,QAAQhC,8CAEZU,cAAce,SAASQ,OACxBA,KAAKC,SAAU,UAGdlB,kCAGRH,0BAA2B,EASpCG,yBAEQb,KAAKG,2BAA2BM,OAAS,OACpCR,2BAA2BG,UAAYJ,KAAKG,wEAIhDO,0BAA2B,kCAU1BsB,KAAO,CACTC,mBAAoBjC,KAAKO,cAAcE,OACvCyB,QAAS,GACTC,YAAa,GACbC,gBAAgB,GAEdC,YAAcrC,KAAKc,iBACnBwB,eAAiBD,YAAY5B,OAAST,KAAKD,wBAG3BwC,QAAQC,IAC1BH,YAAYI,KAAI,CAAClB,WAAYmB,QACzBnB,WAAWoB,wBACPL,gBAAmBI,OAAS1C,KAAKD,WAAa,EAC9C2C,WAMJpB,SAAQ,CAACsB,cAAeF,SACxBJ,gBAAmBI,OAAS1C,KAAKD,WAAa,EAC9CiC,KAAKG,YAAYU,KAAK,eAAkBD,gBAExCZ,KAAKE,QAAQW,KAAK,eAAkBD,mBAI5CZ,KAAKI,eAAiBJ,KAAKG,YAAY1B,OAAS,EAEzCqC,mBAAUC,OAAO,gCAAiCf,4CAUnDgB,oBAAsB,mBAAU,gBAAiB,OAAQhD,KAAKO,cAAcE,QAClFQ,SAASC,cAAcrB,uCAAuCO,UAAY4C"} \ No newline at end of file diff --git a/lib/amd/src/bulkactions/bulk_action.js b/lib/amd/src/bulkactions/bulk_action.js index d92a59f00e1..3b1a5d19177 100644 --- a/lib/amd/src/bulkactions/bulk_action.js +++ b/lib/amd/src/bulkactions/bulk_action.js @@ -78,9 +78,10 @@ export default class BulkAction { * * @method renderBulkActionTrigger * @param {boolean} showInDropdown Whether the action is displayed under a 'More' dropdown or as a separate button. + * @param {number} index The index of the action. * @returns {Promise} */ - renderBulkActionTrigger(showInDropdown = false) { - throw new Error(`renderBulkActionTrigger(${showInDropdown}) must be implemented in ${this.constructor.name}`); + renderBulkActionTrigger(showInDropdown = false, index) { + throw new Error(`renderBulkActionTrigger(${showInDropdown}, ${index}) must be implemented in ${this.constructor.name}`); } } diff --git a/lib/amd/src/bulkactions/bulk_actions.js b/lib/amd/src/bulkactions/bulk_actions.js index 38af0514044..68c04ec5f3d 100644 --- a/lib/amd/src/bulkactions/bulk_actions.js +++ b/lib/amd/src/bulkactions/bulk_actions.js @@ -194,7 +194,11 @@ export default class BulkActions { // Get all bulk actions and render them in order. const actions = await Promise.all( bulkActions.map((bulkAction, index) => - bulkAction.renderBulkActionTrigger(showMoreButton && (index >= this.maxButtons - 1))) + bulkAction.renderBulkActionTrigger( + showMoreButton && (index >= this.maxButtons - 1), + index + ) + ) ); // Separate rendered actions into data.actions and data.moreactions in the correct order. diff --git a/lib/templates/bulkactions/bulk_action_trigger.mustache b/lib/templates/bulkactions/bulk_action_trigger.mustache index 7ee15ad19c3..4d734fb5d27 100644 --- a/lib/templates/bulkactions/bulk_action_trigger.mustache +++ b/lib/templates/bulkactions/bulk_action_trigger.mustache @@ -21,10 +21,12 @@ Context variables required for this template: * showindropdown - Whether the action is displayed under a 'More' dropdown or as a separate button. + * isfirst - Whether the action is the first one in the list. Example context (json): { - "showindropdown": false + "showindropdown": false, + "isfirst": true } }} {{#showindropdown}} @@ -36,6 +38,7 @@ class="btn py-0 d-flex flex-column" data-action="{{$action}}{{/action}}" title="{{$title}}{{/title}}" + {{^isfirst}}tabindex="-1"{{/isfirst}} > {{$icon}}{{/icon}} {{$title}}{{/title}} diff --git a/lib/templates/bulkactions/bulk_actions.mustache b/lib/templates/bulkactions/bulk_actions.mustache index 2bc3f1a9ee5..d7420881391 100644 --- a/lib/templates/bulkactions/bulk_actions.mustache +++ b/lib/templates/bulkactions/bulk_actions.mustache @@ -58,6 +58,7 @@ data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" + tabindex="-1" > {{#pix}} i/menu, core {{/pix}} diff --git a/mod/assign/amd/build/bulkactions/grading/delete.min.js b/mod/assign/amd/build/bulkactions/grading/delete.min.js index 866215f914c..f84fb9f49eb 100644 --- a/mod/assign/amd/build/bulkactions/grading/delete.min.js +++ b/mod/assign/amd/build/bulkactions/grading/delete.min.js @@ -1,3 +1,3 @@ -define("mod_assign/bulkactions/grading/delete",["exports","core/bulkactions/bulk_action","core/notification","core/templates","core/str"],(function(_exports,_bulk_action,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldGet(receiver,privateMap){return function(receiver,descriptor){if(descriptor.get)return descriptor.get.call(receiver);return descriptor.value}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"get"))}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap,_sesskey=new WeakMap;class _default extends _bulk_action.default{constructor(cmid,sesskey){super(),_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_sesskey,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid),_classPrivateFieldSet(this,_sesskey,sesskey)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="removesubmission"]'}async triggerBulkAction(){_notification.default.deleteCancelPromise((0,_str.getString)("removesubmission","mod_assign"),(0,_str.getString)("batchoperationconfirmremovesubmission","mod_assign"),(0,_str.getString)("batchoperationremovesubmission","mod_assign")).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);url.searchParams.set("id",_classPrivateFieldGet(this,_cmid));const form=document.createElement("form");form.method="POST",form.action=url.toString(),((form,hiddenInputs)=>{for(const[name,value]of Object.entries(hiddenInputs)){const input=document.createElement("input");input.type="hidden",input.name=name,input.value=value,form.appendChild(input)}})(form,{action:"gradingbatchoperation",operation:"removesubmission",selectedusers:selectedUsers.join(","),sesskey:_classPrivateFieldGet(this,_sesskey)}),document.body.appendChild(form),form.submit(),form.remove()})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown){return _templates.default.render("mod_assign/bulkactions/grading/bulk_delete_trigger",{showindropdown:showInDropdown})}}return _exports.default=_default,_exports.default})); +define("mod_assign/bulkactions/grading/delete",["exports","core/bulkactions/bulk_action","core/notification","core/templates","core/str"],(function(_exports,_bulk_action,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldGet(receiver,privateMap){return function(receiver,descriptor){if(descriptor.get)return descriptor.get.call(receiver);return descriptor.value}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"get"))}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap,_sesskey=new WeakMap;class _default extends _bulk_action.default{constructor(cmid,sesskey){super(),_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_sesskey,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid),_classPrivateFieldSet(this,_sesskey,sesskey)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="removesubmission"]'}async triggerBulkAction(){_notification.default.deleteCancelPromise((0,_str.getString)("removesubmission","mod_assign"),(0,_str.getString)("batchoperationconfirmremovesubmission","mod_assign"),(0,_str.getString)("batchoperationremovesubmission","mod_assign")).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);url.searchParams.set("id",_classPrivateFieldGet(this,_cmid));const form=document.createElement("form");form.method="POST",form.action=url.toString(),((form,hiddenInputs)=>{for(const[name,value]of Object.entries(hiddenInputs)){const input=document.createElement("input");input.type="hidden",input.name=name,input.value=value,form.appendChild(input)}})(form,{action:"gradingbatchoperation",operation:"removesubmission",selectedusers:selectedUsers.join(","),sesskey:_classPrivateFieldGet(this,_sesskey)}),document.body.appendChild(form),form.submit(),form.remove()})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown,index){return _templates.default.render("mod_assign/bulkactions/grading/bulk_delete_trigger",{showindropdown:showInDropdown,isfirst:0===index})}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=delete.min.js.map \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/delete.min.js.map b/mod/assign/amd/build/bulkactions/grading/delete.min.js.map index 2c3fd5b51fe..197ebf4ff21 100644 --- a/mod/assign/amd/build/bulkactions/grading/delete.min.js.map +++ b/mod/assign/amd/build/bulkactions/grading/delete.min.js.map @@ -1 +1 @@ -{"version":3,"file":"delete.min.js","sources":["../../../src/bulkactions/grading/delete.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 * Class that defines the bulk action for removing submissions in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/delete\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n /** @type {number} The course module ID. */\n #cmid;\n\n /** @type {string} The session key. */\n #sesskey;\n\n /**\n * The class constructor.\n *\n * @param {number} cmid The course module ID.\n * @param {string} sesskey The session key.\n */\n constructor(cmid, sesskey) {\n super();\n this.#cmid = cmid;\n this.#sesskey = sesskey;\n }\n\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"removesubmission\"]';\n }\n\n async triggerBulkAction() {\n Notification.deleteCancelPromise(\n getString('removesubmission', 'mod_assign'),\n getString('batchoperationconfirmremovesubmission', 'mod_assign'),\n getString('batchoperationremovesubmission', 'mod_assign'),\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n\n const form = document.createElement('form');\n form.method = 'POST';\n form.action = url.toString();\n\n // Create hidden inputs for the form.\n ((form, hiddenInputs) => {\n for (const [name, value] of Object.entries(hiddenInputs)) {\n const input = document.createElement('input');\n input.type = 'hidden';\n input.name = name;\n input.value = value;\n form.appendChild(input);\n }\n })(form, {\n action: 'gradingbatchoperation',\n operation: 'removesubmission',\n selectedusers: selectedUsers.join(','),\n sesskey: this.#sesskey,\n });\n\n // Append the form to the body, submit it, and then remove it from the DOM.\n document.body.appendChild(form);\n form.submit();\n form.remove();\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_delete_trigger', {\n showindropdown: showInDropdown,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","sesskey","getBulkActionTriggerSelector","deleteCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","this","form","createElement","method","action","toString","hiddenInputs","name","Object","entries","input","type","appendChild","operation","selectedusers","join","body","submit","remove","catch","showInDropdown","Templates","render","showindropdown"],"mappings":"qhDA4BMA,iCACsB,yHAGCC,qBAazBC,YAAYC,KAAMC,yLAEDD,0CACGC,SAGpBC,qCACW,6GAIMC,qBACT,kBAAU,mBAAoB,eAC9B,kBAAU,wCAAyC,eACnD,kBAAU,iCAAkC,eAC9CC,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBV,mCAAmCW,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,MACpCJ,IAAIK,aAAaC,IAAI,2BAAMC,mBAErBC,KAAOb,SAASc,cAAc,QACpCD,KAAKE,OAAS,OACdF,KAAKG,OAASX,IAAIY,aAGhBJ,KAAMK,oBACC,MAAOC,KAAMf,SAAUgB,OAAOC,QAAQH,cAAe,OAChDI,MAAQtB,SAASc,cAAc,SACrCQ,MAAMC,KAAO,SACbD,MAAMH,KAAOA,KACbG,MAAMlB,MAAQA,MACdS,KAAKW,YAAYF,UAEtBT,KAAM,CACLG,OAAQ,wBACRS,UAAW,mBACXC,cAAe3B,cAAc4B,KAAK,KAClChC,8BAASiB,iBAIbZ,SAAS4B,KAAKJ,YAAYX,MAC1BA,KAAKgB,SACLhB,KAAKiB,YAGNC,OAAM,uCAKiBC,uBACnBC,mBAAUC,OAAO,qDAAsD,CAC1EC,eAAgBH"} \ No newline at end of file +{"version":3,"file":"delete.min.js","sources":["../../../src/bulkactions/grading/delete.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 * Class that defines the bulk action for removing submissions in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/delete\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n /** @type {number} The course module ID. */\n #cmid;\n\n /** @type {string} The session key. */\n #sesskey;\n\n /**\n * The class constructor.\n *\n * @param {number} cmid The course module ID.\n * @param {string} sesskey The session key.\n */\n constructor(cmid, sesskey) {\n super();\n this.#cmid = cmid;\n this.#sesskey = sesskey;\n }\n\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"removesubmission\"]';\n }\n\n async triggerBulkAction() {\n Notification.deleteCancelPromise(\n getString('removesubmission', 'mod_assign'),\n getString('batchoperationconfirmremovesubmission', 'mod_assign'),\n getString('batchoperationremovesubmission', 'mod_assign'),\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n\n const form = document.createElement('form');\n form.method = 'POST';\n form.action = url.toString();\n\n // Create hidden inputs for the form.\n ((form, hiddenInputs) => {\n for (const [name, value] of Object.entries(hiddenInputs)) {\n const input = document.createElement('input');\n input.type = 'hidden';\n input.name = name;\n input.value = value;\n form.appendChild(input);\n }\n })(form, {\n action: 'gradingbatchoperation',\n operation: 'removesubmission',\n selectedusers: selectedUsers.join(','),\n sesskey: this.#sesskey,\n });\n\n // Append the form to the body, submit it, and then remove it from the DOM.\n document.body.appendChild(form);\n form.submit();\n form.remove();\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown, index) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_delete_trigger', {\n showindropdown: showInDropdown,\n isfirst: index === 0,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","sesskey","getBulkActionTriggerSelector","deleteCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","this","form","createElement","method","action","toString","hiddenInputs","name","Object","entries","input","type","appendChild","operation","selectedusers","join","body","submit","remove","catch","showInDropdown","index","Templates","render","showindropdown","isfirst"],"mappings":"qhDA4BMA,iCACsB,yHAGCC,qBAazBC,YAAYC,KAAMC,yLAEDD,0CACGC,SAGpBC,qCACW,6GAIMC,qBACT,kBAAU,mBAAoB,eAC9B,kBAAU,wCAAyC,eACnD,kBAAU,iCAAkC,eAC9CC,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBV,mCAAmCW,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,MACpCJ,IAAIK,aAAaC,IAAI,2BAAMC,mBAErBC,KAAOb,SAASc,cAAc,QACpCD,KAAKE,OAAS,OACdF,KAAKG,OAASX,IAAIY,aAGhBJ,KAAMK,oBACC,MAAOC,KAAMf,SAAUgB,OAAOC,QAAQH,cAAe,OAChDI,MAAQtB,SAASc,cAAc,SACrCQ,MAAMC,KAAO,SACbD,MAAMH,KAAOA,KACbG,MAAMlB,MAAQA,MACdS,KAAKW,YAAYF,UAEtBT,KAAM,CACLG,OAAQ,wBACRS,UAAW,mBACXC,cAAe3B,cAAc4B,KAAK,KAClChC,8BAASiB,iBAIbZ,SAAS4B,KAAKJ,YAAYX,MAC1BA,KAAKgB,SACLhB,KAAKiB,YAGNC,OAAM,uCAKiBC,eAAgBC,cACnCC,mBAAUC,OAAO,qDAAsD,CAC1EC,eAAgBJ,eAChBK,QAAmB,IAAVJ"} \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/extend.min.js b/mod/assign/amd/build/bulkactions/grading/extend.min.js index 8d99704379f..ceae3ea7db9 100644 --- a/mod/assign/amd/build/bulkactions/grading/extend.min.js +++ b/mod/assign/amd/build/bulkactions/grading/extend.min.js @@ -1,3 +1,3 @@ -define("mod_assign/bulkactions/grading/extend",["exports","core/bulkactions/bulk_action","core/notification","core/templates","core/str"],(function(_exports,_bulk_action,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap;class _default extends _bulk_action.default{constructor(cmid){super(),_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="grantextension"]'}async triggerBulkAction(){_notification.default.saveCancelPromise((0,_str.getString)("grantextension","mod_assign"),(0,_str.getString)("batchoperationconfirmgrantextension","mod_assign"),(0,_str.getString)("batchoperationgrantextension","mod_assign")).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);var receiver;url.searchParams.set("id",function(receiver,descriptor){return descriptor.get?descriptor.get.call(receiver):descriptor.value}(receiver=this,_classExtractFieldDescriptor(receiver,_cmid,"get"))),url.searchParams.set("action","grantextension"),url.searchParams.set("selectedusers",selectedUsers.join(",")),window.location=url})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown){return _templates.default.render("mod_assign/bulkactions/grading/bulk_extend_trigger",{showindropdown:showInDropdown})}}return _exports.default=_default,_exports.default})); +define("mod_assign/bulkactions/grading/extend",["exports","core/bulkactions/bulk_action","core/notification","core/templates","core/str"],(function(_exports,_bulk_action,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap;class _default extends _bulk_action.default{constructor(cmid){super(),_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="grantextension"]'}async triggerBulkAction(){_notification.default.saveCancelPromise((0,_str.getString)("grantextension","mod_assign"),(0,_str.getString)("batchoperationconfirmgrantextension","mod_assign"),(0,_str.getString)("batchoperationgrantextension","mod_assign")).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);var receiver;url.searchParams.set("id",function(receiver,descriptor){return descriptor.get?descriptor.get.call(receiver):descriptor.value}(receiver=this,_classExtractFieldDescriptor(receiver,_cmid,"get"))),url.searchParams.set("action","grantextension"),url.searchParams.set("selectedusers",selectedUsers.join(",")),window.location=url})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown,index){return _templates.default.render("mod_assign/bulkactions/grading/bulk_extend_trigger",{showindropdown:showInDropdown,isfirst:0===index})}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=extend.min.js.map \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/extend.min.js.map b/mod/assign/amd/build/bulkactions/grading/extend.min.js.map index d1188e2ebe9..9c2ca911bb5 100644 --- a/mod/assign/amd/build/bulkactions/grading/extend.min.js.map +++ b/mod/assign/amd/build/bulkactions/grading/extend.min.js.map @@ -1 +1 @@ -{"version":3,"file":"extend.min.js","sources":["../../../src/bulkactions/grading/extend.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 * Class that defines the bulk action to extend the assignment deadline in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/extend\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n /** @type {number} The course module ID. */\n #cmid;\n\n /**\n * The class constructor.\n *\n * @param {number} cmid The course module ID.\n */\n constructor(cmid) {\n super();\n this.#cmid = cmid;\n }\n\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"grantextension\"]';\n }\n\n async triggerBulkAction() {\n Notification.saveCancelPromise(\n getString('grantextension', 'mod_assign'),\n getString('batchoperationconfirmgrantextension', 'mod_assign'),\n getString('batchoperationgrantextension', 'mod_assign'),\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n url.searchParams.set('action', 'grantextension');\n url.searchParams.set('selectedusers', selectedUsers.join(','));\n window.location = url;\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_extend_trigger', {\n showindropdown: showInDropdown,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","getBulkActionTriggerSelector","saveCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","this","join","catch","showInDropdown","Templates","render","showindropdown"],"mappings":"0yCA4BMA,iCACsB,oGAGCC,qBASzBC,YAAYC,iHAEKA,MAGjBC,qCACW,2GAIMC,mBACT,kBAAU,iBAAkB,eAC5B,kBAAU,sCAAuC,eACjD,kBAAU,+BAAgC,eAC5CC,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBT,mCAAmCU,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,mBACpCJ,IAAIK,aAAaC,IAAI,kHAAMC,0DAC3BP,IAAIK,aAAaC,IAAI,SAAU,kBAC/BN,IAAIK,aAAaC,IAAI,gBAAiBZ,cAAcc,KAAK,MACzDN,OAAOC,SAAWH,OAGnBS,OAAM,uCAKiBC,uBACnBC,mBAAUC,OAAO,qDAAsD,CAC1EC,eAAgBH"} \ No newline at end of file +{"version":3,"file":"extend.min.js","sources":["../../../src/bulkactions/grading/extend.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 * Class that defines the bulk action to extend the assignment deadline in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/extend\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n /** @type {number} The course module ID. */\n #cmid;\n\n /**\n * The class constructor.\n *\n * @param {number} cmid The course module ID.\n */\n constructor(cmid) {\n super();\n this.#cmid = cmid;\n }\n\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"grantextension\"]';\n }\n\n async triggerBulkAction() {\n Notification.saveCancelPromise(\n getString('grantextension', 'mod_assign'),\n getString('batchoperationconfirmgrantextension', 'mod_assign'),\n getString('batchoperationgrantextension', 'mod_assign'),\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n url.searchParams.set('action', 'grantextension');\n url.searchParams.set('selectedusers', selectedUsers.join(','));\n window.location = url;\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown, index) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_extend_trigger', {\n showindropdown: showInDropdown,\n isfirst: index === 0,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","getBulkActionTriggerSelector","saveCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","this","join","catch","showInDropdown","index","Templates","render","showindropdown","isfirst"],"mappings":"0yCA4BMA,iCACsB,oGAGCC,qBASzBC,YAAYC,iHAEKA,MAGjBC,qCACW,2GAIMC,mBACT,kBAAU,iBAAkB,eAC5B,kBAAU,sCAAuC,eACjD,kBAAU,+BAAgC,eAC5CC,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBT,mCAAmCU,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,mBACpCJ,IAAIK,aAAaC,IAAI,kHAAMC,0DAC3BP,IAAIK,aAAaC,IAAI,SAAU,kBAC/BN,IAAIK,aAAaC,IAAI,gBAAiBZ,cAAcc,KAAK,MACzDN,OAAOC,SAAWH,OAGnBS,OAAM,uCAKiBC,eAAgBC,cACnCC,mBAAUC,OAAO,qDAAsD,CAC1EC,eAAgBJ,eAChBK,QAAmB,IAAVJ"} \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/general_action.min.js b/mod/assign/amd/build/bulkactions/grading/general_action.min.js index 09e4cc9b993..24737cc5ca7 100644 --- a/mod/assign/amd/build/bulkactions/grading/general_action.min.js +++ b/mod/assign/amd/build/bulkactions/grading/general_action.min.js @@ -1,3 +1,3 @@ -define("mod_assign/bulkactions/grading/general_action",["exports","core/bulkactions/bulk_action","core/notification","core/templates"],(function(_exports,_bulk_action,_notification,_templates){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldGet(receiver,privateMap){return function(receiver,descriptor){if(descriptor.get)return descriptor.get.call(receiver);return descriptor.value}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"get"))}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap,_buttonIcon=new WeakMap,_buttonLabel=new WeakMap,_confirmationTitle=new WeakMap,_confirmationQuestion=new WeakMap,_confirmationYes=new WeakMap,_sesskey=new WeakMap;class _default extends _bulk_action.default{constructor(cmid,sesskey,actionKey,buttonLabel,buttonIcon,confirmationTitle,confirmationQuestion,confirmationYes){var obj,key,value;super(),value=void 0,(key="actionKey")in(obj=this)?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_buttonIcon,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_buttonLabel,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_confirmationTitle,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_confirmationQuestion,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_confirmationYes,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_sesskey,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid),_classPrivateFieldSet(this,_sesskey,sesskey),this.actionKey=actionKey,_classPrivateFieldSet(this,_buttonLabel,buttonLabel),_classPrivateFieldSet(this,_buttonIcon,buttonIcon),_classPrivateFieldSet(this,_confirmationTitle,confirmationTitle),_classPrivateFieldSet(this,_confirmationQuestion,confirmationQuestion),_classPrivateFieldSet(this,_confirmationYes,confirmationYes)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="'.concat(this.actionKey,'"]')}async triggerBulkAction(){_notification.default.saveCancelPromise(_classPrivateFieldGet(this,_confirmationTitle),_classPrivateFieldGet(this,_confirmationQuestion),_classPrivateFieldGet(this,_confirmationYes)).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);url.searchParams.set("id",_classPrivateFieldGet(this,_cmid));const form=document.createElement("form");form.method="POST",form.action=url.toString(),((form,hiddenInputs)=>{for(const[name,value]of Object.entries(hiddenInputs)){const input=document.createElement("input");input.type="hidden",input.name=name,input.value=value,form.appendChild(input)}})(form,{action:"gradingbatchoperation",operation:this.actionKey,selectedusers:selectedUsers.join(","),sesskey:_classPrivateFieldGet(this,_sesskey)}),document.body.appendChild(form),form.submit(),form.remove()})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown){return _templates.default.render("mod_assign/bulkactions/grading/bulk_general_action_trigger",{action:this.actionKey,title:await _classPrivateFieldGet(this,_buttonLabel),icon:await _classPrivateFieldGet(this,_buttonIcon),showindropdown:showInDropdown})}}return _exports.default=_default,_exports.default})); +define("mod_assign/bulkactions/grading/general_action",["exports","core/bulkactions/bulk_action","core/notification","core/templates"],(function(_exports,_bulk_action,_notification,_templates){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldGet(receiver,privateMap){return function(receiver,descriptor){if(descriptor.get)return descriptor.get.call(receiver);return descriptor.value}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"get"))}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap,_buttonIcon=new WeakMap,_buttonLabel=new WeakMap,_confirmationTitle=new WeakMap,_confirmationQuestion=new WeakMap,_confirmationYes=new WeakMap,_sesskey=new WeakMap;class _default extends _bulk_action.default{constructor(cmid,sesskey,actionKey,buttonLabel,buttonIcon,confirmationTitle,confirmationQuestion,confirmationYes){var obj,key,value;super(),value=void 0,(key="actionKey")in(obj=this)?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_buttonIcon,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_buttonLabel,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_confirmationTitle,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_confirmationQuestion,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_confirmationYes,{writable:!0,value:void 0}),_classPrivateFieldInitSpec(this,_sesskey,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid),_classPrivateFieldSet(this,_sesskey,sesskey),this.actionKey=actionKey,_classPrivateFieldSet(this,_buttonLabel,buttonLabel),_classPrivateFieldSet(this,_buttonIcon,buttonIcon),_classPrivateFieldSet(this,_confirmationTitle,confirmationTitle),_classPrivateFieldSet(this,_confirmationQuestion,confirmationQuestion),_classPrivateFieldSet(this,_confirmationYes,confirmationYes)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="'.concat(this.actionKey,'"]')}async triggerBulkAction(){_notification.default.saveCancelPromise(_classPrivateFieldGet(this,_confirmationTitle),_classPrivateFieldGet(this,_confirmationQuestion),_classPrivateFieldGet(this,_confirmationYes)).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);url.searchParams.set("id",_classPrivateFieldGet(this,_cmid));const form=document.createElement("form");form.method="POST",form.action=url.toString(),((form,hiddenInputs)=>{for(const[name,value]of Object.entries(hiddenInputs)){const input=document.createElement("input");input.type="hidden",input.name=name,input.value=value,form.appendChild(input)}})(form,{action:"gradingbatchoperation",operation:this.actionKey,selectedusers:selectedUsers.join(","),sesskey:_classPrivateFieldGet(this,_sesskey)}),document.body.appendChild(form),form.submit(),form.remove()})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown,index){return _templates.default.render("mod_assign/bulkactions/grading/bulk_general_action_trigger",{action:this.actionKey,title:await _classPrivateFieldGet(this,_buttonLabel),icon:await _classPrivateFieldGet(this,_buttonIcon),showindropdown:showInDropdown,isfirst:0===index})}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=general_action.min.js.map \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/general_action.min.js.map b/mod/assign/amd/build/bulkactions/grading/general_action.min.js.map index 2ae15269bd7..a66517365b7 100644 --- a/mod/assign/amd/build/bulkactions/grading/general_action.min.js.map +++ b/mod/assign/amd/build/bulkactions/grading/general_action.min.js.map @@ -1 +1 @@ -{"version":3,"file":"general_action.min.js","sources":["../../../src/bulkactions/grading/general_action.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 * Class that defines the bulk action for general actions in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/general_action\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n\n /** @type {string} The action key. */\n actionKey;\n\n /** @type {number} The course module ID. */\n #cmid;\n\n /** @type {Promise} The action button's icon. */\n #buttonIcon;\n\n /** @type {Promise} The action button's label. */\n #buttonLabel;\n\n /** @type {Promise} Title of the confirmation dialog. */\n #confirmationTitle;\n\n /** @type {Promise} Question of the confirmation dialog. */\n #confirmationQuestion;\n\n /** @type {Promise} Text for the confirmation yes button. */\n #confirmationYes;\n\n /** @type {string} The session key. */\n #sesskey;\n\n /**\n * The class constructor.\n *\n * @param {int} cmid The course module ID.\n * @param {string} sesskey The session key.\n * @param {string} actionKey The action key.\n * @param {Promise} buttonLabel The action button's label.\n * @param {Promise} buttonIcon The action button's icon.\n * @param {Promise} confirmationTitle Title of the confirmation dialog.\n * @param {Promise} confirmationQuestion Question of the confirmation dialog.\n * @param {Promise} confirmationYes Text for the confirmation yes button.\n */\n constructor(cmid, sesskey, actionKey, buttonLabel, buttonIcon, confirmationTitle, confirmationQuestion, confirmationYes) {\n super();\n this.#cmid = cmid;\n this.#sesskey = sesskey;\n this.actionKey = actionKey;\n this.#buttonLabel = buttonLabel;\n this.#buttonIcon = buttonIcon;\n this.#confirmationTitle = confirmationTitle;\n this.#confirmationQuestion = confirmationQuestion;\n this.#confirmationYes = confirmationYes;\n }\n\n getBulkActionTriggerSelector() {\n return `[data-type=\"bulkactions\"] [data-action=\"${this.actionKey}\"]`;\n }\n\n async triggerBulkAction() {\n Notification.saveCancelPromise(\n this.#confirmationTitle,\n this.#confirmationQuestion,\n this.#confirmationYes,\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n\n const form = document.createElement('form');\n form.method = 'POST';\n form.action = url.toString();\n\n // Create hidden inputs for the form.\n ((form, hiddenInputs) => {\n for (const [name, value] of Object.entries(hiddenInputs)) {\n const input = document.createElement('input');\n input.type = 'hidden';\n input.name = name;\n input.value = value;\n form.appendChild(input);\n }\n })(form, {\n action: 'gradingbatchoperation',\n operation: this.actionKey,\n selectedusers: selectedUsers.join(','),\n sesskey: this.#sesskey,\n });\n\n // Append the form to the body, submit it, and then remove it from the DOM.\n document.body.appendChild(form);\n form.submit();\n form.remove();\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_general_action_trigger', {\n action: this.actionKey,\n title: await this.#buttonLabel,\n icon: await this.#buttonIcon,\n showindropdown: showInDropdown,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","sesskey","actionKey","buttonLabel","buttonIcon","confirmationTitle","confirmationQuestion","confirmationYes","getBulkActionTriggerSelector","this","saveCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","form","createElement","method","action","toString","hiddenInputs","name","Object","entries","input","type","appendChild","operation","selectedusers","join","body","submit","remove","catch","showInDropdown","Templates","render","title","icon","showindropdown"],"mappings":"6gDA2BMA,iCACsB,wQAGCC,qBAsCzBC,YAAYC,KAAMC,QAASC,UAAWC,YAAaC,WAAYC,kBAAmBC,qBAAsBC,muBAEvFP,0CACGC,cACXC,UAAYA,kDACGC,oDACDC,0DACOC,oEACGC,kEACLC,iBAG5BC,uFACsDC,KAAKP,gEAI1CQ,wCACTD,+CACAA,kDACAA,wBACFE,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBjB,mCAAmCkB,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,MACpCJ,IAAIK,aAAaC,IAAI,2BAAMf,mBAErBgB,KAAOZ,SAASa,cAAc,QACpCD,KAAKE,OAAS,OACdF,KAAKG,OAASV,IAAIW,aAGhBJ,KAAMK,oBACC,MAAOC,KAAMd,SAAUe,OAAOC,QAAQH,cAAe,OAChDI,MAAQrB,SAASa,cAAc,SACrCQ,MAAMC,KAAO,SACbD,MAAMH,KAAOA,KACbG,MAAMjB,MAAQA,MACdQ,KAAKW,YAAYF,UAEtBT,KAAM,CACLG,OAAQ,wBACRS,UAAW5B,KAAKP,UAChBoC,cAAe1B,cAAc2B,KAAK,KAClCtC,8BAASQ,iBAIbI,SAAS2B,KAAKJ,YAAYX,MAC1BA,KAAKgB,SACLhB,KAAKiB,YAGNC,OAAM,uCAKiBC,uBACnBC,mBAAUC,OAAO,6DAA8D,CAClFlB,OAAQnB,KAAKP,UACb6C,kCAAatC,mBACbuC,iCAAYvC,kBACZwC,eAAgBL"} \ No newline at end of file +{"version":3,"file":"general_action.min.js","sources":["../../../src/bulkactions/grading/general_action.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 * Class that defines the bulk action for general actions in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/general_action\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n\n /** @type {string} The action key. */\n actionKey;\n\n /** @type {number} The course module ID. */\n #cmid;\n\n /** @type {Promise} The action button's icon. */\n #buttonIcon;\n\n /** @type {Promise} The action button's label. */\n #buttonLabel;\n\n /** @type {Promise} Title of the confirmation dialog. */\n #confirmationTitle;\n\n /** @type {Promise} Question of the confirmation dialog. */\n #confirmationQuestion;\n\n /** @type {Promise} Text for the confirmation yes button. */\n #confirmationYes;\n\n /** @type {string} The session key. */\n #sesskey;\n\n /**\n * The class constructor.\n *\n * @param {int} cmid The course module ID.\n * @param {string} sesskey The session key.\n * @param {string} actionKey The action key.\n * @param {Promise} buttonLabel The action button's label.\n * @param {Promise} buttonIcon The action button's icon.\n * @param {Promise} confirmationTitle Title of the confirmation dialog.\n * @param {Promise} confirmationQuestion Question of the confirmation dialog.\n * @param {Promise} confirmationYes Text for the confirmation yes button.\n */\n constructor(cmid, sesskey, actionKey, buttonLabel, buttonIcon, confirmationTitle, confirmationQuestion, confirmationYes) {\n super();\n this.#cmid = cmid;\n this.#sesskey = sesskey;\n this.actionKey = actionKey;\n this.#buttonLabel = buttonLabel;\n this.#buttonIcon = buttonIcon;\n this.#confirmationTitle = confirmationTitle;\n this.#confirmationQuestion = confirmationQuestion;\n this.#confirmationYes = confirmationYes;\n }\n\n getBulkActionTriggerSelector() {\n return `[data-type=\"bulkactions\"] [data-action=\"${this.actionKey}\"]`;\n }\n\n async triggerBulkAction() {\n Notification.saveCancelPromise(\n this.#confirmationTitle,\n this.#confirmationQuestion,\n this.#confirmationYes,\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n\n const form = document.createElement('form');\n form.method = 'POST';\n form.action = url.toString();\n\n // Create hidden inputs for the form.\n ((form, hiddenInputs) => {\n for (const [name, value] of Object.entries(hiddenInputs)) {\n const input = document.createElement('input');\n input.type = 'hidden';\n input.name = name;\n input.value = value;\n form.appendChild(input);\n }\n })(form, {\n action: 'gradingbatchoperation',\n operation: this.actionKey,\n selectedusers: selectedUsers.join(','),\n sesskey: this.#sesskey,\n });\n\n // Append the form to the body, submit it, and then remove it from the DOM.\n document.body.appendChild(form);\n form.submit();\n form.remove();\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown, index) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_general_action_trigger', {\n action: this.actionKey,\n title: await this.#buttonLabel,\n icon: await this.#buttonIcon,\n showindropdown: showInDropdown,\n isfirst: index === 0,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","sesskey","actionKey","buttonLabel","buttonIcon","confirmationTitle","confirmationQuestion","confirmationYes","getBulkActionTriggerSelector","this","saveCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","form","createElement","method","action","toString","hiddenInputs","name","Object","entries","input","type","appendChild","operation","selectedusers","join","body","submit","remove","catch","showInDropdown","index","Templates","render","title","icon","showindropdown","isfirst"],"mappings":"6gDA2BMA,iCACsB,wQAGCC,qBAsCzBC,YAAYC,KAAMC,QAASC,UAAWC,YAAaC,WAAYC,kBAAmBC,qBAAsBC,muBAEvFP,0CACGC,cACXC,UAAYA,kDACGC,oDACDC,0DACOC,oEACGC,kEACLC,iBAG5BC,uFACsDC,KAAKP,gEAI1CQ,wCACTD,+CACAA,kDACAA,wBACFE,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBjB,mCAAmCkB,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,MACpCJ,IAAIK,aAAaC,IAAI,2BAAMf,mBAErBgB,KAAOZ,SAASa,cAAc,QACpCD,KAAKE,OAAS,OACdF,KAAKG,OAASV,IAAIW,aAGhBJ,KAAMK,oBACC,MAAOC,KAAMd,SAAUe,OAAOC,QAAQH,cAAe,OAChDI,MAAQrB,SAASa,cAAc,SACrCQ,MAAMC,KAAO,SACbD,MAAMH,KAAOA,KACbG,MAAMjB,MAAQA,MACdQ,KAAKW,YAAYF,UAEtBT,KAAM,CACLG,OAAQ,wBACRS,UAAW5B,KAAKP,UAChBoC,cAAe1B,cAAc2B,KAAK,KAClCtC,8BAASQ,iBAIbI,SAAS2B,KAAKJ,YAAYX,MAC1BA,KAAKgB,SACLhB,KAAKiB,YAGNC,OAAM,uCAKiBC,eAAgBC,cACnCC,mBAAUC,OAAO,6DAA8D,CAClFnB,OAAQnB,KAAKP,UACb8C,kCAAavC,mBACbwC,iCAAYxC,kBACZyC,eAAgBN,eAChBO,QAAmB,IAAVN"} \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/message.min.js b/mod/assign/amd/build/bulkactions/grading/message.min.js index e4277cccebf..802cf9c3a84 100644 --- a/mod/assign/amd/build/bulkactions/grading/message.min.js +++ b/mod/assign/amd/build/bulkactions/grading/message.min.js @@ -5,6 +5,6 @@ define("mod_assign/bulkactions/grading/message",["exports","core/bulkactions/bul * @module mod_assign/bulkactions/grading/message * @copyright 2024 Shamim Rezaie * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';class _default extends _bulk_action.default{getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="message"]'}triggerBulkAction(){const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value));(0,_message_send_bulk.showModal)(selectedUsers)}async renderBulkActionTrigger(showInDropdown){return _templates.default.render("mod_assign/bulkactions/grading/bulk_message_trigger",{showindropdown:showInDropdown})}}return _exports.default=_default,_exports.default})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';class _default extends _bulk_action.default{getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="message"]'}triggerBulkAction(){const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value));(0,_message_send_bulk.showModal)(selectedUsers)}async renderBulkActionTrigger(showInDropdown,index){return _templates.default.render("mod_assign/bulkactions/grading/bulk_message_trigger",{showindropdown:showInDropdown,isfirst:0===index})}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=message.min.js.map \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/message.min.js.map b/mod/assign/amd/build/bulkactions/grading/message.min.js.map index d8aa84fe33c..e399f77838a 100644 --- a/mod/assign/amd/build/bulkactions/grading/message.min.js.map +++ b/mod/assign/amd/build/bulkactions/grading/message.min.js.map @@ -1 +1 @@ -{"version":3,"file":"message.min.js","sources":["../../../src/bulkactions/grading/message.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 * Bulk action for messaging users in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/message\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Templates from 'core/templates';\nimport {showModal as showMessageModal} from 'core_message/message_send_bulk';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"message\"]';\n }\n\n triggerBulkAction() {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n showMessageModal(selectedUsers);\n }\n\n async renderBulkActionTrigger(showInDropdown) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_message_trigger', {\n showindropdown: showInDropdown,\n });\n }\n}\n"],"names":["Selectors","BulkAction","getBulkActionTriggerSelector","triggerBulkAction","selectedUsers","document","querySelectorAll","map","checkbox","value","showInDropdown","Templates","render","showindropdown"],"mappings":";;;;;;;2LA2BMA,iCACsB,8EAGCC,qBACzBC,qCACW,oDAGVC,0BACSC,cAAgB,IAAIC,SAASC,iBAAiBN,mCAAmCO,KAAIC,UAAYA,SAASC,yCAC9FL,6CAGQM,uBACnBC,mBAAUC,OAAO,sDAAuD,CAC3EC,eAAgBH"} \ No newline at end of file +{"version":3,"file":"message.min.js","sources":["../../../src/bulkactions/grading/message.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 * Bulk action for messaging users in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/message\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Templates from 'core/templates';\nimport {showModal as showMessageModal} from 'core_message/message_send_bulk';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"message\"]';\n }\n\n triggerBulkAction() {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n showMessageModal(selectedUsers);\n }\n\n async renderBulkActionTrigger(showInDropdown, index) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_message_trigger', {\n showindropdown: showInDropdown,\n isfirst: index === 0,\n });\n }\n}\n"],"names":["Selectors","BulkAction","getBulkActionTriggerSelector","triggerBulkAction","selectedUsers","document","querySelectorAll","map","checkbox","value","showInDropdown","index","Templates","render","showindropdown","isfirst"],"mappings":";;;;;;;2LA2BMA,iCACsB,8EAGCC,qBACzBC,qCACW,oDAGVC,0BACSC,cAAgB,IAAIC,SAASC,iBAAiBN,mCAAmCO,KAAIC,UAAYA,SAASC,yCAC9FL,6CAGQM,eAAgBC,cACnCC,mBAAUC,OAAO,sDAAuD,CAC3EC,eAAgBJ,eAChBK,QAAmB,IAAVJ"} \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/setmarkingallocation.min.js b/mod/assign/amd/build/bulkactions/grading/setmarkingallocation.min.js index a2f0d58e255..cf47bc1f118 100644 --- a/mod/assign/amd/build/bulkactions/grading/setmarkingallocation.min.js +++ b/mod/assign/amd/build/bulkactions/grading/setmarkingallocation.min.js @@ -1,3 +1,3 @@ -define("mod_assign/bulkactions/grading/setmarkingallocation",["exports","core/bulkactions/bulk_action","core/notification","core/templates","core/str"],(function(_exports,_bulk_action,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap;class _default extends _bulk_action.default{constructor(cmid){super(),_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="setmarkingallocation"]'}async triggerBulkAction(){_notification.default.saveCancelPromise((0,_str.getString)("setmarkingallocation","mod_assign"),(0,_str.getString)("batchoperationconfirmsetmarkingallocation","mod_assign"),(0,_str.getString)("batchoperationsetmarkingallocation","mod_assign")).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);var receiver;url.searchParams.set("id",function(receiver,descriptor){return descriptor.get?descriptor.get.call(receiver):descriptor.value}(receiver=this,_classExtractFieldDescriptor(receiver,_cmid,"get"))),url.searchParams.set("action","viewbatchmarkingallocation"),url.searchParams.set("selectedusers",selectedUsers.join(",")),window.location=url})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown){return _templates.default.render("mod_assign/bulkactions/grading/bulk_setmarkingallocation_trigger",{showindropdown:showInDropdown})}}return _exports.default=_default,_exports.default})); +define("mod_assign/bulkactions/grading/setmarkingallocation",["exports","core/bulkactions/bulk_action","core/notification","core/templates","core/str"],(function(_exports,_bulk_action,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap;class _default extends _bulk_action.default{constructor(cmid){super(),_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="setmarkingallocation"]'}async triggerBulkAction(){_notification.default.saveCancelPromise((0,_str.getString)("setmarkingallocation","mod_assign"),(0,_str.getString)("batchoperationconfirmsetmarkingallocation","mod_assign"),(0,_str.getString)("batchoperationsetmarkingallocation","mod_assign")).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);var receiver;url.searchParams.set("id",function(receiver,descriptor){return descriptor.get?descriptor.get.call(receiver):descriptor.value}(receiver=this,_classExtractFieldDescriptor(receiver,_cmid,"get"))),url.searchParams.set("action","viewbatchmarkingallocation"),url.searchParams.set("selectedusers",selectedUsers.join(",")),window.location=url})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown,index){return _templates.default.render("mod_assign/bulkactions/grading/bulk_setmarkingallocation_trigger",{showindropdown:showInDropdown,isfirst:0===index})}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=setmarkingallocation.min.js.map \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/setmarkingallocation.min.js.map b/mod/assign/amd/build/bulkactions/grading/setmarkingallocation.min.js.map index c18089b96b7..a58dd3318ee 100644 --- a/mod/assign/amd/build/bulkactions/grading/setmarkingallocation.min.js.map +++ b/mod/assign/amd/build/bulkactions/grading/setmarkingallocation.min.js.map @@ -1 +1 @@ -{"version":3,"file":"setmarkingallocation.min.js","sources":["../../../src/bulkactions/grading/setmarkingallocation.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 * Bulk action for allocating markers in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/setmarkingallocation\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n /** @type {number} The course module ID. */\n #cmid;\n\n /**\n * The class constructor.\n *\n * @param {number} cmid The course module ID.\n */\n constructor(cmid) {\n super();\n this.#cmid = cmid;\n }\n\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"setmarkingallocation\"]';\n }\n\n async triggerBulkAction() {\n Notification.saveCancelPromise(\n getString('setmarkingallocation', 'mod_assign'),\n getString('batchoperationconfirmsetmarkingallocation', 'mod_assign'),\n getString('batchoperationsetmarkingallocation', 'mod_assign'),\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n url.searchParams.set('action', 'viewbatchmarkingallocation');\n url.searchParams.set('selectedusers', selectedUsers.join(','));\n window.location = url;\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_setmarkingallocation_trigger', {\n showindropdown: showInDropdown,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","getBulkActionTriggerSelector","saveCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","this","join","catch","showInDropdown","Templates","render","showindropdown"],"mappings":"wzCA4BMA,iCACsB,oGAGCC,qBASzBC,YAAYC,iHAEKA,MAGjBC,qCACW,iHAIMC,mBACT,kBAAU,uBAAwB,eAClC,kBAAU,4CAA6C,eACvD,kBAAU,qCAAsC,eAClDC,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBT,mCAAmCU,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,mBACpCJ,IAAIK,aAAaC,IAAI,kHAAMC,0DAC3BP,IAAIK,aAAaC,IAAI,SAAU,8BAC/BN,IAAIK,aAAaC,IAAI,gBAAiBZ,cAAcc,KAAK,MACzDN,OAAOC,SAAWH,OAGnBS,OAAM,uCAKiBC,uBACnBC,mBAAUC,OAAO,mEAAoE,CACxFC,eAAgBH"} \ No newline at end of file +{"version":3,"file":"setmarkingallocation.min.js","sources":["../../../src/bulkactions/grading/setmarkingallocation.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 * Bulk action for allocating markers in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/setmarkingallocation\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n /** @type {number} The course module ID. */\n #cmid;\n\n /**\n * The class constructor.\n *\n * @param {number} cmid The course module ID.\n */\n constructor(cmid) {\n super();\n this.#cmid = cmid;\n }\n\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"setmarkingallocation\"]';\n }\n\n async triggerBulkAction() {\n Notification.saveCancelPromise(\n getString('setmarkingallocation', 'mod_assign'),\n getString('batchoperationconfirmsetmarkingallocation', 'mod_assign'),\n getString('batchoperationsetmarkingallocation', 'mod_assign'),\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n url.searchParams.set('action', 'viewbatchmarkingallocation');\n url.searchParams.set('selectedusers', selectedUsers.join(','));\n window.location = url;\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown, index) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_setmarkingallocation_trigger', {\n showindropdown: showInDropdown,\n isfirst: index === 0,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","getBulkActionTriggerSelector","saveCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","this","join","catch","showInDropdown","index","Templates","render","showindropdown","isfirst"],"mappings":"wzCA4BMA,iCACsB,oGAGCC,qBASzBC,YAAYC,iHAEKA,MAGjBC,qCACW,iHAIMC,mBACT,kBAAU,uBAAwB,eAClC,kBAAU,4CAA6C,eACvD,kBAAU,qCAAsC,eAClDC,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBT,mCAAmCU,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,mBACpCJ,IAAIK,aAAaC,IAAI,kHAAMC,0DAC3BP,IAAIK,aAAaC,IAAI,SAAU,8BAC/BN,IAAIK,aAAaC,IAAI,gBAAiBZ,cAAcc,KAAK,MACzDN,OAAOC,SAAWH,OAGnBS,OAAM,uCAKiBC,eAAgBC,cACnCC,mBAAUC,OAAO,mEAAoE,CACxFC,eAAgBJ,eAChBK,QAAmB,IAAVJ"} \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/setmarkingworkflowstate.min.js b/mod/assign/amd/build/bulkactions/grading/setmarkingworkflowstate.min.js index 8061b804b42..fe22f7604ce 100644 --- a/mod/assign/amd/build/bulkactions/grading/setmarkingworkflowstate.min.js +++ b/mod/assign/amd/build/bulkactions/grading/setmarkingworkflowstate.min.js @@ -1,3 +1,3 @@ -define("mod_assign/bulkactions/grading/setmarkingworkflowstate",["exports","core/bulkactions/bulk_action","core/notification","core/templates","core/str"],(function(_exports,_bulk_action,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap;class _default extends _bulk_action.default{constructor(cmid){super(),_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="setmarkingworkflowstate"]'}async triggerBulkAction(){_notification.default.saveCancelPromise((0,_str.getString)("setmarkingworkflowstate","mod_assign"),(0,_str.getString)("batchoperationconfirmsetmarkingworkflowstate","mod_assign"),(0,_str.getString)("batchoperationsetmarkingworkflowstate","mod_assign")).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);var receiver;url.searchParams.set("id",function(receiver,descriptor){return descriptor.get?descriptor.get.call(receiver):descriptor.value}(receiver=this,_classExtractFieldDescriptor(receiver,_cmid,"get"))),url.searchParams.set("action","viewbatchsetmarkingworkflowstate"),url.searchParams.set("selectedusers",selectedUsers.join(",")),window.location=url})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown){return _templates.default.render("mod_assign/bulkactions/grading/bulk_setmarkingworkflowstate_trigger",{showindropdown:showInDropdown})}}return _exports.default=_default,_exports.default})); +define("mod_assign/bulkactions/grading/setmarkingworkflowstate",["exports","core/bulkactions/bulk_action","core/notification","core/templates","core/str"],(function(_exports,_bulk_action,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _classPrivateFieldInitSpec(obj,privateMap,value){!function(obj,privateCollection){if(privateCollection.has(obj))throw new TypeError("Cannot initialize the same private elements twice on an object")}(obj,privateMap),privateMap.set(obj,value)}function _classPrivateFieldSet(receiver,privateMap,value){return function(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_bulk_action=_interopRequireDefault(_bulk_action),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const Selectors_selectBulkItemCheckbox='input[type="checkbox"][name="selectedusers"]:checked';var _cmid=new WeakMap;class _default extends _bulk_action.default{constructor(cmid){super(),_classPrivateFieldInitSpec(this,_cmid,{writable:!0,value:void 0}),_classPrivateFieldSet(this,_cmid,cmid)}getBulkActionTriggerSelector(){return'[data-type="bulkactions"] [data-action="setmarkingworkflowstate"]'}async triggerBulkAction(){_notification.default.saveCancelPromise((0,_str.getString)("setmarkingworkflowstate","mod_assign"),(0,_str.getString)("batchoperationconfirmsetmarkingworkflowstate","mod_assign"),(0,_str.getString)("batchoperationsetmarkingworkflowstate","mod_assign")).then((()=>{const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),url=new URL(window.location.href);var receiver;url.searchParams.set("id",function(receiver,descriptor){return descriptor.get?descriptor.get.call(receiver):descriptor.value}(receiver=this,_classExtractFieldDescriptor(receiver,_cmid,"get"))),url.searchParams.set("action","viewbatchsetmarkingworkflowstate"),url.searchParams.set("selectedusers",selectedUsers.join(",")),window.location=url})).catch((()=>{}))}async renderBulkActionTrigger(showInDropdown,index){return _templates.default.render("mod_assign/bulkactions/grading/bulk_setmarkingworkflowstate_trigger",{showindropdown:showInDropdown,isfirst:0===index})}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=setmarkingworkflowstate.min.js.map \ No newline at end of file diff --git a/mod/assign/amd/build/bulkactions/grading/setmarkingworkflowstate.min.js.map b/mod/assign/amd/build/bulkactions/grading/setmarkingworkflowstate.min.js.map index cfef1afac79..4b741f96947 100644 --- a/mod/assign/amd/build/bulkactions/grading/setmarkingworkflowstate.min.js.map +++ b/mod/assign/amd/build/bulkactions/grading/setmarkingworkflowstate.min.js.map @@ -1 +1 @@ -{"version":3,"file":"setmarkingworkflowstate.min.js","sources":["../../../src/bulkactions/grading/setmarkingworkflowstate.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 * Class that defines the bulk action for setting marking workflow state in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/setmarkingworkflowstate\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n /** @type {number} The course module ID. */\n #cmid;\n\n /**\n * The class constructor.\n *\n * @param {number} cmid The course module ID.\n */\n constructor(cmid) {\n super();\n this.#cmid = cmid;\n }\n\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"setmarkingworkflowstate\"]';\n }\n\n async triggerBulkAction() {\n Notification.saveCancelPromise(\n getString('setmarkingworkflowstate', 'mod_assign'),\n getString('batchoperationconfirmsetmarkingworkflowstate', 'mod_assign'),\n getString('batchoperationsetmarkingworkflowstate', 'mod_assign'),\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n url.searchParams.set('action', 'viewbatchsetmarkingworkflowstate');\n url.searchParams.set('selectedusers', selectedUsers.join(','));\n window.location = url;\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_setmarkingworkflowstate_trigger', {\n showindropdown: showInDropdown,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","getBulkActionTriggerSelector","saveCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","this","join","catch","showInDropdown","Templates","render","showindropdown"],"mappings":"2zCA4BMA,iCACsB,oGAGCC,qBASzBC,YAAYC,iHAEKA,MAGjBC,qCACW,oHAIMC,mBACT,kBAAU,0BAA2B,eACrC,kBAAU,+CAAgD,eAC1D,kBAAU,wCAAyC,eACrDC,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBT,mCAAmCU,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,mBACpCJ,IAAIK,aAAaC,IAAI,kHAAMC,0DAC3BP,IAAIK,aAAaC,IAAI,SAAU,oCAC/BN,IAAIK,aAAaC,IAAI,gBAAiBZ,cAAcc,KAAK,MACzDN,OAAOC,SAAWH,OAGnBS,OAAM,uCAKiBC,uBACnBC,mBAAUC,OAAO,sEAAuE,CAC3FC,eAAgBH"} \ No newline at end of file +{"version":3,"file":"setmarkingworkflowstate.min.js","sources":["../../../src/bulkactions/grading/setmarkingworkflowstate.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 * Class that defines the bulk action for setting marking workflow state in the assignment grading page.\n *\n * @module mod_assign/bulkactions/grading/setmarkingworkflowstate\n * @copyright 2024 Shamim Rezaie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BulkAction from 'core/bulkactions/bulk_action';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"][name=\"selectedusers\"]:checked',\n};\n\nexport default class extends BulkAction {\n /** @type {number} The course module ID. */\n #cmid;\n\n /**\n * The class constructor.\n *\n * @param {number} cmid The course module ID.\n */\n constructor(cmid) {\n super();\n this.#cmid = cmid;\n }\n\n getBulkActionTriggerSelector() {\n return '[data-type=\"bulkactions\"] [data-action=\"setmarkingworkflowstate\"]';\n }\n\n async triggerBulkAction() {\n Notification.saveCancelPromise(\n getString('setmarkingworkflowstate', 'mod_assign'),\n getString('batchoperationconfirmsetmarkingworkflowstate', 'mod_assign'),\n getString('batchoperationsetmarkingworkflowstate', 'mod_assign'),\n ).then(() => {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n const url = new URL(window.location.href);\n url.searchParams.set('id', this.#cmid);\n url.searchParams.set('action', 'viewbatchsetmarkingworkflowstate');\n url.searchParams.set('selectedusers', selectedUsers.join(','));\n window.location = url;\n\n return;\n }).catch(() => {\n return;\n });\n }\n\n async renderBulkActionTrigger(showInDropdown, index) {\n return Templates.render('mod_assign/bulkactions/grading/bulk_setmarkingworkflowstate_trigger', {\n showindropdown: showInDropdown,\n isfirst: index === 0,\n });\n }\n}\n"],"names":["Selectors","BulkAction","constructor","cmid","getBulkActionTriggerSelector","saveCancelPromise","then","selectedUsers","document","querySelectorAll","map","checkbox","value","url","URL","window","location","href","searchParams","set","this","join","catch","showInDropdown","index","Templates","render","showindropdown","isfirst"],"mappings":"2zCA4BMA,iCACsB,oGAGCC,qBASzBC,YAAYC,iHAEKA,MAGjBC,qCACW,oHAIMC,mBACT,kBAAU,0BAA2B,eACrC,kBAAU,+CAAgD,eAC1D,kBAAU,wCAAyC,eACrDC,MAAK,WACGC,cAAgB,IAAIC,SAASC,iBAAiBT,mCAAmCU,KAAIC,UAAYA,SAASC,QAC1GC,IAAM,IAAIC,IAAIC,OAAOC,SAASC,mBACpCJ,IAAIK,aAAaC,IAAI,kHAAMC,0DAC3BP,IAAIK,aAAaC,IAAI,SAAU,oCAC/BN,IAAIK,aAAaC,IAAI,gBAAiBZ,cAAcc,KAAK,MACzDN,OAAOC,SAAWH,OAGnBS,OAAM,uCAKiBC,eAAgBC,cACnCC,mBAAUC,OAAO,sEAAuE,CAC3FC,eAAgBJ,eAChBK,QAAmB,IAAVJ"} \ No newline at end of file diff --git a/mod/assign/amd/src/bulkactions/grading/delete.js b/mod/assign/amd/src/bulkactions/grading/delete.js index 9dd93e6838b..0b76730a188 100644 --- a/mod/assign/amd/src/bulkactions/grading/delete.js +++ b/mod/assign/amd/src/bulkactions/grading/delete.js @@ -94,9 +94,10 @@ export default class extends BulkAction { }); } - async renderBulkActionTrigger(showInDropdown) { + async renderBulkActionTrigger(showInDropdown, index) { return Templates.render('mod_assign/bulkactions/grading/bulk_delete_trigger', { showindropdown: showInDropdown, + isfirst: index === 0, }); } } diff --git a/mod/assign/amd/src/bulkactions/grading/extend.js b/mod/assign/amd/src/bulkactions/grading/extend.js index 5e0140e7096..49e77b7c3eb 100644 --- a/mod/assign/amd/src/bulkactions/grading/extend.js +++ b/mod/assign/amd/src/bulkactions/grading/extend.js @@ -67,9 +67,10 @@ export default class extends BulkAction { }); } - async renderBulkActionTrigger(showInDropdown) { + async renderBulkActionTrigger(showInDropdown, index) { return Templates.render('mod_assign/bulkactions/grading/bulk_extend_trigger', { showindropdown: showInDropdown, + isfirst: index === 0, }); } } diff --git a/mod/assign/amd/src/bulkactions/grading/general_action.js b/mod/assign/amd/src/bulkactions/grading/general_action.js index 6896af8a815..18065174bb8 100644 --- a/mod/assign/amd/src/bulkactions/grading/general_action.js +++ b/mod/assign/amd/src/bulkactions/grading/general_action.js @@ -124,12 +124,13 @@ export default class extends BulkAction { }); } - async renderBulkActionTrigger(showInDropdown) { + async renderBulkActionTrigger(showInDropdown, index) { return Templates.render('mod_assign/bulkactions/grading/bulk_general_action_trigger', { action: this.actionKey, title: await this.#buttonLabel, icon: await this.#buttonIcon, showindropdown: showInDropdown, + isfirst: index === 0, }); } } diff --git a/mod/assign/amd/src/bulkactions/grading/message.js b/mod/assign/amd/src/bulkactions/grading/message.js index 2b7289bac53..79ee9179960 100644 --- a/mod/assign/amd/src/bulkactions/grading/message.js +++ b/mod/assign/amd/src/bulkactions/grading/message.js @@ -39,9 +39,10 @@ export default class extends BulkAction { showMessageModal(selectedUsers); } - async renderBulkActionTrigger(showInDropdown) { + async renderBulkActionTrigger(showInDropdown, index) { return Templates.render('mod_assign/bulkactions/grading/bulk_message_trigger', { showindropdown: showInDropdown, + isfirst: index === 0, }); } } diff --git a/mod/assign/amd/src/bulkactions/grading/setmarkingallocation.js b/mod/assign/amd/src/bulkactions/grading/setmarkingallocation.js index 4fd5c7a6496..66ad7f951ab 100644 --- a/mod/assign/amd/src/bulkactions/grading/setmarkingallocation.js +++ b/mod/assign/amd/src/bulkactions/grading/setmarkingallocation.js @@ -67,9 +67,10 @@ export default class extends BulkAction { }); } - async renderBulkActionTrigger(showInDropdown) { + async renderBulkActionTrigger(showInDropdown, index) { return Templates.render('mod_assign/bulkactions/grading/bulk_setmarkingallocation_trigger', { showindropdown: showInDropdown, + isfirst: index === 0, }); } } diff --git a/mod/assign/amd/src/bulkactions/grading/setmarkingworkflowstate.js b/mod/assign/amd/src/bulkactions/grading/setmarkingworkflowstate.js index 981e64455f6..4067b6e581e 100644 --- a/mod/assign/amd/src/bulkactions/grading/setmarkingworkflowstate.js +++ b/mod/assign/amd/src/bulkactions/grading/setmarkingworkflowstate.js @@ -67,9 +67,10 @@ export default class extends BulkAction { }); } - async renderBulkActionTrigger(showInDropdown) { + async renderBulkActionTrigger(showInDropdown, index) { return Templates.render('mod_assign/bulkactions/grading/bulk_setmarkingworkflowstate_trigger', { showindropdown: showInDropdown, + isfirst: index === 0, }); } } diff --git a/mod/assign/templates/bulkactions/grading/bulk_delete_trigger.mustache b/mod/assign/templates/bulkactions/grading/bulk_delete_trigger.mustache index c4c31ace92c..aeb283b005f 100644 --- a/mod/assign/templates/bulkactions/grading/bulk_delete_trigger.mustache +++ b/mod/assign/templates/bulkactions/grading/bulk_delete_trigger.mustache @@ -21,10 +21,12 @@ Context variables required for this template: * showindropdown - Whether the action is displayed under a 'More' dropdown or as a separate button. + * isfirst - Whether the action is the first one in the list. Example context (json): { - "showindropdown": false + "showindropdown": false, + "isfirst": true } }} {{< core/bulkactions/bulk_action_trigger }} diff --git a/mod/assign/templates/bulkactions/grading/bulk_extend_trigger.mustache b/mod/assign/templates/bulkactions/grading/bulk_extend_trigger.mustache index f9bb83adfdb..02fcfbe2397 100644 --- a/mod/assign/templates/bulkactions/grading/bulk_extend_trigger.mustache +++ b/mod/assign/templates/bulkactions/grading/bulk_extend_trigger.mustache @@ -21,10 +21,12 @@ Context variables required for this template: * showindropdown - Whether the action is displayed under a 'More' dropdown or as a separate button. + * isfirst - Whether the action is the first one in the list. Example context (json): { - "showindropdown": false + "showindropdown": false, + "isfirst": true } }} {{< core/bulkactions/bulk_action_trigger }} diff --git a/mod/assign/templates/bulkactions/grading/bulk_general_action_trigger.mustache b/mod/assign/templates/bulkactions/grading/bulk_general_action_trigger.mustache index 279fe21b609..8eea5eea453 100644 --- a/mod/assign/templates/bulkactions/grading/bulk_general_action_trigger.mustache +++ b/mod/assign/templates/bulkactions/grading/bulk_general_action_trigger.mustache @@ -24,13 +24,15 @@ * title: The title of the action button. * icon: The icon of the action button. * showindropdown - Whether the action is displayed under a 'More' dropdown or as a separate button. + * isfirst - Whether the action is the first one in the list. Example context (json): { "action": "lock", "title": "Lock", "icon": "", - "showindropdown": false + "showindropdown": false, + "isfirst": true } }} {{< core/bulkactions/bulk_action_trigger }} diff --git a/mod/assign/templates/bulkactions/grading/bulk_message_trigger.mustache b/mod/assign/templates/bulkactions/grading/bulk_message_trigger.mustache index 3334f013ec9..ec84b0b861a 100644 --- a/mod/assign/templates/bulkactions/grading/bulk_message_trigger.mustache +++ b/mod/assign/templates/bulkactions/grading/bulk_message_trigger.mustache @@ -21,10 +21,12 @@ Context variables required for this template: * showindropdown - Whether the action is displayed under a 'More' dropdown or as a separate button. + * isfirst - Whether the action is the first one in the list. Example context (json): { - "showindropdown": false + "showindropdown": false, + "isfirst": true } }} {{< core/bulkactions/bulk_action_trigger }} diff --git a/mod/assign/templates/bulkactions/grading/bulk_setmarkingallocation_trigger.mustache b/mod/assign/templates/bulkactions/grading/bulk_setmarkingallocation_trigger.mustache index d68c180f90e..407e8f20b09 100644 --- a/mod/assign/templates/bulkactions/grading/bulk_setmarkingallocation_trigger.mustache +++ b/mod/assign/templates/bulkactions/grading/bulk_setmarkingallocation_trigger.mustache @@ -21,10 +21,12 @@ Context variables required for this template: * showindropdown - Whether the action is displayed under a 'More' dropdown or as a separate button. + * isfirst - Whether the action is the first one in the list. Example context (json): { - "showindropdown": false + "showindropdown": false, + "isfirst": true } }} {{< core/bulkactions/bulk_action_trigger }} diff --git a/mod/assign/templates/bulkactions/grading/bulk_setmarkingworkflowstate_trigger.mustache b/mod/assign/templates/bulkactions/grading/bulk_setmarkingworkflowstate_trigger.mustache index f5ba5ca5c0f..c9c1816084b 100644 --- a/mod/assign/templates/bulkactions/grading/bulk_setmarkingworkflowstate_trigger.mustache +++ b/mod/assign/templates/bulkactions/grading/bulk_setmarkingworkflowstate_trigger.mustache @@ -21,10 +21,12 @@ Context variables required for this template: * showindropdown - Whether the action is displayed under a 'More' dropdown or as a separate button. + * isfirst - Whether the action is the first one in the list. Example context (json): { - "showindropdown": false + "showindropdown": false, + "isfirst": true } }} {{< core/bulkactions/bulk_action_trigger }} diff --git a/theme/boost/amd/build/aria.min.js b/theme/boost/amd/build/aria.min.js index ffa384d39e3..a42112bb648 100644 --- a/theme/boost/amd/build/aria.min.js +++ b/theme/boost/amd/build/aria.min.js @@ -5,6 +5,6 @@ define("theme_boost/aria",["exports","jquery","core/pending","core/local/aria/fo * @module theme_boost/aria * @copyright 2018 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_jquery=_interopRequireDefault(_jquery),_pending=_interopRequireDefault(_pending),FocusLockManager=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}(FocusLockManager);const dropdownFix=()=>{let focusEnd=!1;const setFocusEnd=function(){let end=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];focusEnd=end},shiftFocus=function(element){let focusCheck=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;const pendingPromise=new _pending.default("core/aria:delayed-focus");setTimeout((()=>{focusCheck&&!focusCheck()||element.focus(),pendingPromise.resolve()}),50)},handleMenuButton=e=>{const trigger=e.key;let fixFocus=!1;if(" "!==trigger&&"Enter"!==trigger||(fixFocus=!0,e.preventDefault(),e.target.click()),"ArrowUp"!==trigger&&"ArrowDown"!==trigger||(fixFocus=!0),!fixFocus)return;const menu=e.target.parentElement.querySelector('[role="menu"]');let menuItems=!1,foundMenuItem=!1;menu&&(menuItems=menu.querySelectorAll('[role="menuitem"]')),menuItems&&menuItems.length>0&&("ArrowUp"===trigger?setFocusEnd():setFocusEnd(!1),foundMenuItem=(()=>{const result=focusEnd;return focusEnd=!1,result})()?menuItems[menuItems.length-1]:menuItems[0]),foundMenuItem&&shiftFocus(foundMenuItem)};document.addEventListener("keypress",(e=>{if(e.target.matches('[role="menu"] [role="menuitem"]')){const menu=e.target.closest('[role="menu"]');if(!menu)return;const menuItems=menu.querySelectorAll('[role="menuitem"]');if(!menuItems)return;const trigger=e.key.toLowerCase();for(let i=0;i{if(e.target.matches('[data-toggle="dropdown"]')&&handleMenuButton(e),e.target.matches('[role="menu"] [role="menuitem"]')){const trigger=e.key;let next=!1;const menu=e.target.closest('[role="menu"]');if(!menu)return;const menuItems=menu.querySelectorAll('[role="menuitem"]');if(!menuItems)return;if("ArrowDown"==trigger){for(let i=0;i{const dialog=e.target.querySelector('.dropdown-menu[role="dialog"]');dialog&&setTimeout((()=>{FocusLockManager.trapFocus(dialog)}))})),(0,_jquery.default)(document).on("hidden.bs.dropdown",(e=>{var _e$clickEvent;e.target.querySelector('.dropdown-menu[role="dialog"]')&&FocusLockManager.untrapFocus();const trigger=e.target.querySelector('[data-toggle="dropdown"]'),focused=(null===(_e$clickEvent=e.clickEvent)||void 0===_e$clickEvent?void 0:_e$clickEvent.target)||(document.activeElement!==document.body?document.activeElement:null);trigger&&focused&&e.target.contains(focused)&&shiftFocus(trigger,(()=>document.activeElement===document.body||e.target.contains(document.activeElement)))}))},tabElementFix=()=>{document.addEventListener("keydown",(e=>{["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","Home","End"].includes(e.key)&&e.target.matches('[role="tablist"] [role="tab"]')&&(e=>{const tabList=e.target.closest('[role="tablist"]'),vertical="vertical"==tabList.getAttribute("aria-orientation"),rtl=window.right_to_left(),arrowNext=vertical?"ArrowDown":rtl?"ArrowLeft":"ArrowRight",arrowPrevious=vertical?"ArrowUp":rtl?"ArrowRight":"ArrowLeft",tabs=Array.prototype.filter.call(tabList.querySelectorAll('[role="tab"]'),(tab=>!!tab.offsetHeight));for(let i=0;i{if(e.target.matches('[role="tablist"] [data-toggle="tab"], [role="tablist"] [data-toggle="pill"]')){const tabs=e.target.closest('[role="tablist"]').querySelectorAll('[data-toggle="tab"], [data-toggle="pill"]');e.preventDefault(),(0,_jquery.default)(e.target).tab("show"),tabs.forEach((tab=>{tab.tabIndex=-1})),e.target.tabIndex=0}}))};_exports.init=()=>{dropdownFix(),(()=>{(0,_jquery.default)(document).on("show.bs.dropdown",(e=>{if(e.relatedTarget.matches('[role="combobox"]')){const combobox=e.relatedTarget,listbox=document.querySelector("#".concat(combobox.getAttribute("aria-controls"),'[role="listbox"]'));if(listbox){const selectedOption=listbox.querySelector('[role="option"][aria-selected="true"]');setTimeout((()=>{if(selectedOption)selectedOption.classList.add("active"),combobox.setAttribute("aria-activedescendant",selectedOption.id);else{const firstOption=listbox.querySelector('[role="option"]');firstOption.setAttribute("aria-selected","true"),firstOption.classList.add("active"),combobox.setAttribute("aria-activedescendant",firstOption.id)}}),0)}}})),(0,_jquery.default)(document).on("hidden.bs.dropdown",(e=>{if(e.relatedTarget.matches('[role="combobox"]')){const combobox=e.relatedTarget,listbox=document.querySelector("#".concat(combobox.getAttribute("aria-controls"),'[role="listbox"]'));combobox.removeAttribute("aria-activedescendant"),listbox&&setTimeout((()=>{listbox.querySelectorAll('.active[role="option"]').forEach((option=>{option.classList.remove("active")}))}),0)}})),document.addEventListener("keydown",(e=>{if(e.target.matches('[role="combobox"][aria-controls]:not([aria-haspopup=dialog])')){const combobox=e.target,trigger=e.key;let next=null;const listbox=document.querySelector("#".concat(combobox.getAttribute("aria-controls"),'[role="listbox"]')),options=listbox.querySelectorAll('[role="option"]'),activeOption=listbox.querySelector('.active[role="option"]'),editable=combobox.hasAttribute("aria-autocomplete");if(options&&(activeOption||editable)){if("ArrowDown"==trigger){for(let i=0;i{const option=e.target.closest('[role="listbox"] [role="option"]');if(option){const listbox=option.closest('[role="listbox"]'),combobox=document.querySelector('[role="combobox"][aria-controls="'.concat(listbox.id,'"]'));combobox&&selectOption(combobox,option)}})),document.addEventListener("change",(e=>{if(e.target.matches('input[type="hidden"][id]')){const combobox=document.querySelector('[role="combobox"][data-input-element="'.concat(e.target.id,'"]')),option=e.target.parentElement.querySelector('[role="option"][data-value="'.concat(e.target.value,'"]'));combobox&&option&&selectOption(combobox,option)}}));const selectOption=(combobox,option)=>{const oldSelectedOption=option.closest('[role="listbox"]').querySelector('[role="option"][aria-selected="true"]');if(oldSelectedOption!=option&&(oldSelectedOption&&oldSelectedOption.removeAttribute("aria-selected"),option.setAttribute("aria-selected","true")),combobox.hasAttribute("value"))combobox.value=option.dataset.shortText||option.textContent.replace(/[\n\r]+|[\s]{2,}/g," ").trim();else{const selectedOptionContainer=combobox.querySelector("[data-selected-option]");selectedOptionContainer?selectedOptionContainer.textContent=option.dataset.shortText||option.textContent:combobox.textContent=option.dataset.shortText||option.textContent}if(combobox.dataset.inputElement){const inputElement=document.getElementById(combobox.dataset.inputElement);inputElement&&inputElement.value!=option.dataset.value&&(inputElement.value=option.dataset.value,inputElement.dispatchEvent(new Event("change",{bubbles:!0})))}}})(),window.addEventListener("load",(()=>{const alerts=document.querySelectorAll('[data-aria-autofocus="true"][role="alert"]');Array.prototype.forEach.call(alerts,(autofocusElement=>{autofocusElement.innerHTML+=" ",autofocusElement.removeAttribute("data-aria-autofocus")}))})),tabElementFix(),document.addEventListener("keydown",(e=>{e.target.matches('[data-toggle="collapse"]')&&" "===e.key&&(e.preventDefault(),e.target.click())}))}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_jquery=_interopRequireDefault(_jquery),_pending=_interopRequireDefault(_pending),FocusLockManager=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}(FocusLockManager);const dropdownFix=()=>{let focusEnd=!1;const setFocusEnd=function(){let end=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];focusEnd=end},shiftFocus=function(element){let focusCheck=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;const pendingPromise=new _pending.default("core/aria:delayed-focus");setTimeout((()=>{focusCheck&&!focusCheck()||element.focus(),pendingPromise.resolve()}),50)},handleMenuButton=e=>{const trigger=e.key;let fixFocus=!1;if(" "!==trigger&&"Enter"!==trigger||(fixFocus=!0,e.preventDefault(),e.target.click()),"ArrowUp"!==trigger&&"ArrowDown"!==trigger||(fixFocus=!0),!fixFocus)return;const menu=e.target.parentElement.querySelector('[role="menu"]');let menuItems=!1,foundMenuItem=!1;menu&&(menuItems=menu.querySelectorAll('[role="menuitem"]')),menuItems&&menuItems.length>0&&("ArrowUp"===trigger?setFocusEnd():setFocusEnd(!1),foundMenuItem=(()=>{const result=focusEnd;return focusEnd=!1,result})()?menuItems[menuItems.length-1]:menuItems[0]),foundMenuItem&&shiftFocus(foundMenuItem)};document.addEventListener("keypress",(e=>{if(e.target.matches('[role="menu"] [role="menuitem"]')){const menu=e.target.closest('[role="menu"]');if(!menu)return;const menuItems=menu.querySelectorAll('[role="menuitem"]');if(!menuItems)return;const trigger=e.key.toLowerCase();for(let i=0;i{if(e.target.matches('[data-toggle="dropdown"]')&&handleMenuButton(e),e.target.matches('[role="menu"] [role="menuitem"]')){const trigger=e.key;let next=!1;const menu=e.target.closest('[role="menu"]');if(!menu)return;const menuItems=menu.querySelectorAll('[role="menuitem"]');if(!menuItems)return;if("ArrowDown"==trigger){for(let i=0;i{const dialog=e.target.querySelector('.dropdown-menu[role="dialog"]');dialog&&setTimeout((()=>{FocusLockManager.trapFocus(dialog)}))})),(0,_jquery.default)(document).on("hidden.bs.dropdown",(e=>{var _e$clickEvent;e.target.querySelector('.dropdown-menu[role="dialog"]')&&FocusLockManager.untrapFocus();const trigger=e.target.querySelector('[data-toggle="dropdown"]'),focused=(null===(_e$clickEvent=e.clickEvent)||void 0===_e$clickEvent?void 0:_e$clickEvent.target)||(document.activeElement!==document.body?document.activeElement:null);trigger&&focused&&e.target.contains(focused)&&shiftFocus(trigger,(()=>document.activeElement===document.body||e.target.contains(document.activeElement)))}))},rovingFocus=(elements,e,vertical,updateTabIndex)=>{const rtl=window.right_to_left(),arrowNext=vertical?"ArrowDown":rtl?"ArrowLeft":"ArrowRight",arrowPrevious=vertical?"ArrowUp":rtl?"ArrowRight":"ArrowLeft";if(![arrowNext,arrowPrevious,"Home","End"].includes(e.key))return;const focusElement=index=>{elements[index].focus(),updateTabIndex&&elements.forEach(((element,i)=>element.setAttribute("tabindex",i===index?"0":"-1")))},currentIndex=Array.prototype.indexOf.call(elements,e.target);let nextIndex;switch(e.key){case arrowNext:e.preventDefault(),nextIndex=currentIndex+1=0?currentIndex-1:elements.length-1,focusElement(nextIndex);break;case"Home":e.preventDefault(),focusElement(0);break;case"End":e.preventDefault(),focusElement(elements.length-1)}};_exports.init=()=>{dropdownFix(),(()=>{(0,_jquery.default)(document).on("show.bs.dropdown",(e=>{if(e.relatedTarget.matches('[role="combobox"]')){const combobox=e.relatedTarget,listbox=document.querySelector("#".concat(combobox.getAttribute("aria-controls"),'[role="listbox"]'));if(listbox){const selectedOption=listbox.querySelector('[role="option"][aria-selected="true"]');setTimeout((()=>{if(selectedOption)selectedOption.classList.add("active"),combobox.setAttribute("aria-activedescendant",selectedOption.id);else{const firstOption=listbox.querySelector('[role="option"]');firstOption.setAttribute("aria-selected","true"),firstOption.classList.add("active"),combobox.setAttribute("aria-activedescendant",firstOption.id)}}),0)}}})),(0,_jquery.default)(document).on("hidden.bs.dropdown",(e=>{if(e.relatedTarget.matches('[role="combobox"]')){const combobox=e.relatedTarget,listbox=document.querySelector("#".concat(combobox.getAttribute("aria-controls"),'[role="listbox"]'));combobox.removeAttribute("aria-activedescendant"),listbox&&setTimeout((()=>{listbox.querySelectorAll('.active[role="option"]').forEach((option=>{option.classList.remove("active")}))}),0)}})),document.addEventListener("keydown",(e=>{if(e.target.matches('[role="combobox"][aria-controls]:not([aria-haspopup=dialog])')){const combobox=e.target,trigger=e.key;let next=null;const listbox=document.querySelector("#".concat(combobox.getAttribute("aria-controls"),'[role="listbox"]')),options=listbox.querySelectorAll('[role="option"]'),activeOption=listbox.querySelector('.active[role="option"]'),editable=combobox.hasAttribute("aria-autocomplete");if(options&&(activeOption||editable)){if("ArrowDown"==trigger){for(let i=0;i{const option=e.target.closest('[role="listbox"] [role="option"]');if(option){const listbox=option.closest('[role="listbox"]'),combobox=document.querySelector('[role="combobox"][aria-controls="'.concat(listbox.id,'"]'));combobox&&selectOption(combobox,option)}})),document.addEventListener("change",(e=>{if(e.target.matches('input[type="hidden"][id]')){const combobox=document.querySelector('[role="combobox"][data-input-element="'.concat(e.target.id,'"]')),option=e.target.parentElement.querySelector('[role="option"][data-value="'.concat(e.target.value,'"]'));combobox&&option&&selectOption(combobox,option)}}));const selectOption=(combobox,option)=>{const oldSelectedOption=option.closest('[role="listbox"]').querySelector('[role="option"][aria-selected="true"]');if(oldSelectedOption!=option&&(oldSelectedOption&&oldSelectedOption.removeAttribute("aria-selected"),option.setAttribute("aria-selected","true")),combobox.hasAttribute("value"))combobox.value=option.dataset.shortText||option.textContent.replace(/[\n\r]+|[\s]{2,}/g," ").trim();else{const selectedOptionContainer=combobox.querySelector("[data-selected-option]");selectedOptionContainer?selectedOptionContainer.textContent=option.dataset.shortText||option.textContent:combobox.textContent=option.dataset.shortText||option.textContent}if(combobox.dataset.inputElement){const inputElement=document.getElementById(combobox.dataset.inputElement);inputElement&&inputElement.value!=option.dataset.value&&(inputElement.value=option.dataset.value,inputElement.dispatchEvent(new Event("change",{bubbles:!0})))}}})(),window.addEventListener("load",(()=>{const alerts=document.querySelectorAll('[data-aria-autofocus="true"][role="alert"]');Array.prototype.forEach.call(alerts,(autofocusElement=>{autofocusElement.innerHTML+=" ",autofocusElement.removeAttribute("data-aria-autofocus")}))})),document.addEventListener("keydown",(e=>{if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","Home","End"].includes(e.key)&&e.target.matches('[role="tablist"] [role="tab"]')){const tabList=e.target.closest('[role="tablist"]'),tabs=Array.prototype.filter.call(tabList.querySelectorAll('[role="tab"]'),(tab=>!!tab.offsetHeight)),vertical="vertical"==tabList.getAttribute("aria-orientation");rovingFocus(tabs,e,vertical,!1)}})),document.addEventListener("click",(e=>{if(e.target.matches('[role="tablist"] [data-toggle="tab"], [role="tablist"] [data-toggle="pill"]')){const tabs=e.target.closest('[role="tablist"]').querySelectorAll('[data-toggle="tab"], [data-toggle="pill"]');e.preventDefault(),(0,_jquery.default)(e.target).tab("show"),tabs.forEach((tab=>{tab.tabIndex=-1})),e.target.tabIndex=0}})),document.addEventListener("keydown",(e=>{e.target.matches('[data-toggle="collapse"]')&&" "===e.key&&(e.preventDefault(),e.target.click())})),document.addEventListener("keydown",(e=>{if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","Home","End"].includes(e.key)&&e.target.matches('[role="toolbar"] button')){const buttons=e.target.closest('[role="toolbar"]').querySelectorAll("button");rovingFocus(buttons,e,!1,!0)}}))}})); //# sourceMappingURL=aria.min.js.map \ No newline at end of file diff --git a/theme/boost/amd/build/aria.min.js.map b/theme/boost/amd/build/aria.min.js.map index 10b7e3ff108..4f4e21fdd9d 100644 --- a/theme/boost/amd/build/aria.min.js.map +++ b/theme/boost/amd/build/aria.min.js.map @@ -1 +1 @@ -{"version":3,"file":"aria.min.js","sources":["../src/aria.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 * Enhancements to Bootstrap components for accessibility.\n *\n * @module theme_boost/aria\n * @copyright 2018 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport Pending from 'core/pending';\nimport * as FocusLockManager from 'core/local/aria/focuslock';\n\n/**\n * Drop downs from bootstrap don't support keyboard accessibility by default.\n */\nconst dropdownFix = () => {\n let focusEnd = false;\n const setFocusEnd = (end = true) => {\n focusEnd = end;\n };\n const getFocusEnd = () => {\n const result = focusEnd;\n focusEnd = false;\n return result;\n };\n\n // Special handling for navigation keys when menu is open.\n const shiftFocus = (element, focusCheck = null) => {\n const pendingPromise = new Pending('core/aria:delayed-focus');\n setTimeout(() => {\n if (!focusCheck || focusCheck()) {\n element.focus();\n }\n\n pendingPromise.resolve();\n }, 50);\n };\n\n // Event handling for the dropdown menu button.\n const handleMenuButton = e => {\n const trigger = e.key;\n let fixFocus = false;\n\n // Space key or Enter key opens the menu.\n if (trigger === ' ' || trigger === 'Enter') {\n fixFocus = true;\n // Cancel random scroll.\n e.preventDefault();\n // Open the menu instead.\n e.target.click();\n }\n\n // Up and Down keys also open the menu.\n if (trigger === 'ArrowUp' || trigger === 'ArrowDown') {\n fixFocus = true;\n }\n\n if (!fixFocus) {\n // No need to fix the focus. Return early.\n return;\n }\n\n // Fix the focus on the menu items when the menu is opened.\n const menu = e.target.parentElement.querySelector('[role=\"menu\"]');\n let menuItems = false;\n let foundMenuItem = false;\n\n if (menu) {\n menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n }\n if (menuItems && menuItems.length > 0) {\n // Up key opens the menu at the end.\n if (trigger === 'ArrowUp') {\n setFocusEnd();\n } else {\n setFocusEnd(false);\n }\n\n if (getFocusEnd()) {\n foundMenuItem = menuItems[menuItems.length - 1];\n } else {\n // The first menu entry, pretty reasonable.\n foundMenuItem = menuItems[0];\n }\n }\n\n if (foundMenuItem) {\n shiftFocus(foundMenuItem);\n }\n };\n\n // Search for menu items by finding the first item that has\n // text starting with the typed character (case insensitive).\n document.addEventListener('keypress', e => {\n if (e.target.matches('[role=\"menu\"] [role=\"menuitem\"]')) {\n const menu = e.target.closest('[role=\"menu\"]');\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n\n const trigger = e.key.toLowerCase();\n\n for (let i = 0; i < menuItems.length; i++) {\n const item = menuItems[i];\n const itemText = item.text.trim().toLowerCase();\n if (itemText.indexOf(trigger) == 0) {\n shiftFocus(item);\n break;\n }\n }\n }\n });\n\n // Keyboard navigation for arrow keys, home and end keys.\n document.addEventListener('keydown', e => {\n\n // We only want to set focus when users access the dropdown via keyboard as per\n // guidelines defined in w3 aria practices 1.1 menu-button.\n if (e.target.matches('[data-toggle=\"dropdown\"]')) {\n handleMenuButton(e);\n }\n\n if (e.target.matches('[role=\"menu\"] [role=\"menuitem\"]')) {\n const trigger = e.key;\n let next = false;\n const menu = e.target.closest('[role=\"menu\"]');\n\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n // Down key.\n if (trigger == 'ArrowDown') {\n for (let i = 0; i < menuItems.length - 1; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i + 1];\n break;\n }\n }\n if (!next) {\n // Wrap to first item.\n next = menuItems[0];\n }\n } else if (trigger == 'ArrowUp') {\n // Up key.\n for (let i = 1; i < menuItems.length; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i - 1];\n break;\n }\n }\n if (!next) {\n // Wrap to last item.\n next = menuItems[menuItems.length - 1];\n }\n } else if (trigger == 'Home') {\n // Home key.\n next = menuItems[0];\n\n } else if (trigger == 'End') {\n // End key.\n next = menuItems[menuItems.length - 1];\n }\n\n // Variable next is set if we do want to act on the keypress.\n if (next) {\n e.preventDefault();\n shiftFocus(next);\n }\n return;\n }\n });\n\n // Trap focus if the dropdown is a dialog.\n $(document).on('shown.bs.dropdown', e => {\n const dialog = e.target.querySelector('.dropdown-menu[role=\"dialog\"]');\n if (dialog) {\n // Use setTimeout to make sure the dialog is positioned correctly to prevent random scrolling.\n setTimeout(() => {\n FocusLockManager.trapFocus(dialog);\n });\n }\n });\n\n // Untrap focus when the dialog dropdown is closed.\n $(document).on('hidden.bs.dropdown', e => {\n const dialog = e.target.querySelector('.dropdown-menu[role=\"dialog\"]');\n if (dialog) {\n FocusLockManager.untrapFocus();\n }\n\n // We need to focus on the menu trigger.\n const trigger = e.target.querySelector('[data-toggle=\"dropdown\"]');\n // If it's a click event, then no element is focused because the clicked element is inside a closed dropdown.\n const focused = e.clickEvent?.target || (document.activeElement !== document.body ? document.activeElement : null);\n if (trigger && focused && e.target.contains(focused)) {\n shiftFocus(trigger, () => {\n if (document.activeElement === document.body) {\n // If the focus is currently on the body, then we can safely assume that the focus needs to be updated.\n return true;\n }\n\n // If the focus is on a child of the clicked element still, then update the focus.\n return e.target.contains(document.activeElement);\n });\n }\n });\n};\n\n/**\n * A lot of Bootstrap's out of the box features don't work if dropdown items are not focusable.\n */\nconst comboboxFix = () => {\n $(document).on('show.bs.dropdown', e => {\n if (e.relatedTarget.matches('[role=\"combobox\"]')) {\n const combobox = e.relatedTarget;\n const listbox = document.querySelector(`#${combobox.getAttribute('aria-controls')}[role=\"listbox\"]`);\n\n if (listbox) {\n const selectedOption = listbox.querySelector('[role=\"option\"][aria-selected=\"true\"]');\n\n // To make sure ArrowDown doesn't move the active option afterwards.\n setTimeout(() => {\n if (selectedOption) {\n selectedOption.classList.add('active');\n combobox.setAttribute('aria-activedescendant', selectedOption.id);\n } else {\n const firstOption = listbox.querySelector('[role=\"option\"]');\n firstOption.setAttribute('aria-selected', 'true');\n firstOption.classList.add('active');\n combobox.setAttribute('aria-activedescendant', firstOption.id);\n }\n }, 0);\n }\n }\n });\n\n $(document).on('hidden.bs.dropdown', e => {\n if (e.relatedTarget.matches('[role=\"combobox\"]')) {\n const combobox = e.relatedTarget;\n const listbox = document.querySelector(`#${combobox.getAttribute('aria-controls')}[role=\"listbox\"]`);\n\n combobox.removeAttribute('aria-activedescendant');\n\n if (listbox) {\n setTimeout(() => {\n // Undo all previously highlighted options.\n listbox.querySelectorAll('.active[role=\"option\"]').forEach(option => {\n option.classList.remove('active');\n });\n }, 0);\n }\n }\n });\n\n // Handling keyboard events for both navigating through and selecting options.\n document.addEventListener('keydown', e => {\n if (e.target.matches('[role=\"combobox\"][aria-controls]:not([aria-haspopup=dialog])')) {\n const combobox = e.target;\n const trigger = e.key;\n let next = null;\n const listbox = document.querySelector(`#${combobox.getAttribute('aria-controls')}[role=\"listbox\"]`);\n const options = listbox.querySelectorAll('[role=\"option\"]');\n const activeOption = listbox.querySelector('.active[role=\"option\"]');\n const editable = combobox.hasAttribute('aria-autocomplete');\n\n // Under the special case that the dropdown menu is being shown as a result of the key press (like when the user\n // presses ArrowDown or Enter or ... to open the dropdown menu), activeOption is not set yet.\n // It's because of a race condition with show.bs.dropdown event handler.\n if (options && (activeOption || editable)) {\n if (trigger == 'ArrowDown') {\n for (let i = 0; i < options.length - 1; i++) {\n if (options[i] == activeOption) {\n next = options[i + 1];\n break;\n }\n }\n if (editable && !next) {\n next = options[0];\n }\n } if (trigger == 'ArrowUp') {\n for (let i = 1; i < options.length; i++) {\n if (options[i] == activeOption) {\n next = options[i - 1];\n break;\n }\n }\n if (editable && !next) {\n next = options[options.length - 1];\n }\n } else if (trigger == 'Home' && !editable) {\n next = options[0];\n } else if (trigger == 'End' && !editable) {\n next = options[options.length - 1];\n } else if ((trigger == ' ' && !editable) || trigger == 'Enter') {\n e.preventDefault();\n selectOption(combobox, activeOption);\n } else if (!editable) {\n // Search for options by finding the first option that has\n // text starting with the typed character (case insensitive).\n for (let i = 0; i < options.length; i++) {\n const option = options[i];\n const optionText = option.textContent.trim().toLowerCase();\n const keyPressed = e.key.toLowerCase();\n if (optionText.indexOf(keyPressed) == 0) {\n next = option;\n break;\n }\n }\n }\n\n // Variable next is set if we do want to act on the keypress.\n if (next) {\n e.preventDefault();\n if (activeOption) {\n activeOption.classList.remove('active');\n }\n next.classList.add('active');\n combobox.setAttribute('aria-activedescendant', next.id);\n next.scrollIntoView({block: 'nearest'});\n }\n }\n }\n });\n\n document.addEventListener('click', e => {\n const option = e.target.closest('[role=\"listbox\"] [role=\"option\"]');\n if (option) {\n const listbox = option.closest('[role=\"listbox\"]');\n const combobox = document.querySelector(`[role=\"combobox\"][aria-controls=\"${listbox.id}\"]`);\n if (combobox) {\n selectOption(combobox, option);\n }\n }\n });\n\n // In case some code somewhere else changes the value of the combobox.\n document.addEventListener('change', e => {\n if (e.target.matches('input[type=\"hidden\"][id]')) {\n const combobox = document.querySelector(`[role=\"combobox\"][data-input-element=\"${e.target.id}\"]`);\n const option = e.target.parentElement.querySelector(`[role=\"option\"][data-value=\"${e.target.value}\"]`);\n\n if (combobox && option) {\n selectOption(combobox, option);\n }\n }\n });\n\n const selectOption = (combobox, option) => {\n const listbox = option.closest('[role=\"listbox\"]');\n const oldSelectedOption = listbox.querySelector('[role=\"option\"][aria-selected=\"true\"]');\n\n if (oldSelectedOption != option) {\n if (oldSelectedOption) {\n oldSelectedOption.removeAttribute('aria-selected');\n }\n option.setAttribute('aria-selected', 'true');\n }\n\n if (combobox.hasAttribute('value')) {\n combobox.value = option.dataset.shortText || option.textContent.replace(/[\\n\\r]+|[\\s]{2,}/g, ' ').trim();\n } else {\n const selectedOptionContainer = combobox.querySelector('[data-selected-option]');\n if (selectedOptionContainer) {\n selectedOptionContainer.textContent = option.dataset.shortText || option.textContent;\n } else {\n combobox.textContent = option.dataset.shortText || option.textContent;\n }\n }\n\n if (combobox.dataset.inputElement) {\n const inputElement = document.getElementById(combobox.dataset.inputElement);\n if (inputElement && (inputElement.value != option.dataset.value)) {\n inputElement.value = option.dataset.value;\n inputElement.dispatchEvent(new Event('change', {bubbles: true}));\n }\n }\n };\n};\n\n/**\n * After page load, focus on any element with special autofocus attribute.\n */\nconst autoFocus = () => {\n window.addEventListener(\"load\", () => {\n const alerts = document.querySelectorAll('[data-aria-autofocus=\"true\"][role=\"alert\"]');\n Array.prototype.forEach.call(alerts, autofocusElement => {\n // According to the specification an role=\"alert\" region is only read out on change to the content\n // of that region.\n autofocusElement.innerHTML += ' ';\n autofocusElement.removeAttribute('data-aria-autofocus');\n });\n });\n};\n\n/**\n * Changes the focus to the correct tab based on the key that is pressed.\n * @param {KeyboardEvent} e\n */\nconst updateTabFocus = e => {\n const tabList = e.target.closest('[role=\"tablist\"]');\n const vertical = tabList.getAttribute('aria-orientation') == 'vertical';\n const rtl = window.right_to_left();\n const arrowNext = vertical ? 'ArrowDown' : (rtl ? 'ArrowLeft' : 'ArrowRight');\n const arrowPrevious = vertical ? 'ArrowUp' : (rtl ? 'ArrowRight' : 'ArrowLeft');\n const tabs = Array.prototype.filter.call(\n tabList.querySelectorAll('[role=\"tab\"]'),\n tab => !!tab.offsetHeight); // We only work with the visible tabs.\n\n for (let i = 0; i < tabs.length; i++) {\n tabs[i].index = i;\n }\n\n switch (e.key) {\n case arrowNext:\n e.preventDefault();\n if (e.target.index !== undefined && tabs[e.target.index + 1]) {\n tabs[e.target.index + 1].focus();\n } else {\n tabs[0].focus();\n }\n break;\n case arrowPrevious:\n e.preventDefault();\n if (e.target.index !== undefined && tabs[e.target.index - 1]) {\n tabs[e.target.index - 1].focus();\n } else {\n tabs[tabs.length - 1].focus();\n }\n break;\n case 'Home':\n e.preventDefault();\n tabs[0].focus();\n break;\n case 'End':\n e.preventDefault();\n tabs[tabs.length - 1].focus();\n }\n};\n\n/**\n * Fix accessibility issues regarding tab elements focus and their tab order in Bootstrap navs.\n */\nconst tabElementFix = () => {\n document.addEventListener('keydown', e => {\n if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) {\n if (e.target.matches('[role=\"tablist\"] [role=\"tab\"]')) {\n updateTabFocus(e);\n }\n }\n });\n\n document.addEventListener('click', e => {\n if (e.target.matches('[role=\"tablist\"] [data-toggle=\"tab\"], [role=\"tablist\"] [data-toggle=\"pill\"]')) {\n const tabs = e.target.closest('[role=\"tablist\"]').querySelectorAll('[data-toggle=\"tab\"], [data-toggle=\"pill\"]');\n e.preventDefault();\n $(e.target).tab('show');\n tabs.forEach(tab => {\n tab.tabIndex = -1;\n });\n e.target.tabIndex = 0;\n }\n });\n};\n\n/**\n * Fix keyboard interaction with Bootstrap Collapse elements.\n *\n * @see {@link https://www.w3.org/TR/wai-aria-practices-1.1/#disclosure|WAI-ARIA Authoring Practices 1.1 - Disclosure (Show/Hide)}\n */\nconst collapseFix = () => {\n document.addEventListener('keydown', e => {\n if (e.target.matches('[data-toggle=\"collapse\"]')) {\n // Pressing space should toggle expand/collapse.\n if (e.key === ' ') {\n e.preventDefault();\n e.target.click();\n }\n }\n });\n};\n\nexport const init = () => {\n dropdownFix();\n comboboxFix();\n autoFocus();\n tabElementFix();\n collapseFix();\n};\n"],"names":["dropdownFix","focusEnd","setFocusEnd","end","shiftFocus","element","focusCheck","pendingPromise","Pending","setTimeout","focus","resolve","handleMenuButton","e","trigger","key","fixFocus","preventDefault","target","click","menu","parentElement","querySelector","menuItems","foundMenuItem","querySelectorAll","length","result","getFocusEnd","document","addEventListener","matches","closest","toLowerCase","i","item","text","trim","indexOf","next","on","dialog","FocusLockManager","trapFocus","untrapFocus","focused","clickEvent","activeElement","body","contains","tabElementFix","includes","tabList","vertical","getAttribute","rtl","window","right_to_left","arrowNext","arrowPrevious","tabs","Array","prototype","filter","call","tab","offsetHeight","index","undefined","updateTabFocus","forEach","tabIndex","relatedTarget","combobox","listbox","selectedOption","classList","add","setAttribute","id","firstOption","removeAttribute","option","remove","options","activeOption","editable","hasAttribute","selectOption","optionText","textContent","keyPressed","scrollIntoView","block","value","oldSelectedOption","dataset","shortText","replace","selectedOptionContainer","inputElement","getElementById","dispatchEvent","Event","bubbles","comboboxFix","alerts","autofocusElement","innerHTML"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"aria.min.js","sources":["../src/aria.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 * Enhancements to Bootstrap components for accessibility.\n *\n * @module theme_boost/aria\n * @copyright 2018 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport Pending from 'core/pending';\nimport * as FocusLockManager from 'core/local/aria/focuslock';\n\n/**\n * Drop downs from bootstrap don't support keyboard accessibility by default.\n */\nconst dropdownFix = () => {\n let focusEnd = false;\n const setFocusEnd = (end = true) => {\n focusEnd = end;\n };\n const getFocusEnd = () => {\n const result = focusEnd;\n focusEnd = false;\n return result;\n };\n\n // Special handling for navigation keys when menu is open.\n const shiftFocus = (element, focusCheck = null) => {\n const pendingPromise = new Pending('core/aria:delayed-focus');\n setTimeout(() => {\n if (!focusCheck || focusCheck()) {\n element.focus();\n }\n\n pendingPromise.resolve();\n }, 50);\n };\n\n // Event handling for the dropdown menu button.\n const handleMenuButton = e => {\n const trigger = e.key;\n let fixFocus = false;\n\n // Space key or Enter key opens the menu.\n if (trigger === ' ' || trigger === 'Enter') {\n fixFocus = true;\n // Cancel random scroll.\n e.preventDefault();\n // Open the menu instead.\n e.target.click();\n }\n\n // Up and Down keys also open the menu.\n if (trigger === 'ArrowUp' || trigger === 'ArrowDown') {\n fixFocus = true;\n }\n\n if (!fixFocus) {\n // No need to fix the focus. Return early.\n return;\n }\n\n // Fix the focus on the menu items when the menu is opened.\n const menu = e.target.parentElement.querySelector('[role=\"menu\"]');\n let menuItems = false;\n let foundMenuItem = false;\n\n if (menu) {\n menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n }\n if (menuItems && menuItems.length > 0) {\n // Up key opens the menu at the end.\n if (trigger === 'ArrowUp') {\n setFocusEnd();\n } else {\n setFocusEnd(false);\n }\n\n if (getFocusEnd()) {\n foundMenuItem = menuItems[menuItems.length - 1];\n } else {\n // The first menu entry, pretty reasonable.\n foundMenuItem = menuItems[0];\n }\n }\n\n if (foundMenuItem) {\n shiftFocus(foundMenuItem);\n }\n };\n\n // Search for menu items by finding the first item that has\n // text starting with the typed character (case insensitive).\n document.addEventListener('keypress', e => {\n if (e.target.matches('[role=\"menu\"] [role=\"menuitem\"]')) {\n const menu = e.target.closest('[role=\"menu\"]');\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n\n const trigger = e.key.toLowerCase();\n\n for (let i = 0; i < menuItems.length; i++) {\n const item = menuItems[i];\n const itemText = item.text.trim().toLowerCase();\n if (itemText.indexOf(trigger) == 0) {\n shiftFocus(item);\n break;\n }\n }\n }\n });\n\n // Keyboard navigation for arrow keys, home and end keys.\n document.addEventListener('keydown', e => {\n\n // We only want to set focus when users access the dropdown via keyboard as per\n // guidelines defined in w3 aria practices 1.1 menu-button.\n if (e.target.matches('[data-toggle=\"dropdown\"]')) {\n handleMenuButton(e);\n }\n\n if (e.target.matches('[role=\"menu\"] [role=\"menuitem\"]')) {\n const trigger = e.key;\n let next = false;\n const menu = e.target.closest('[role=\"menu\"]');\n\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n // Down key.\n if (trigger == 'ArrowDown') {\n for (let i = 0; i < menuItems.length - 1; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i + 1];\n break;\n }\n }\n if (!next) {\n // Wrap to first item.\n next = menuItems[0];\n }\n } else if (trigger == 'ArrowUp') {\n // Up key.\n for (let i = 1; i < menuItems.length; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i - 1];\n break;\n }\n }\n if (!next) {\n // Wrap to last item.\n next = menuItems[menuItems.length - 1];\n }\n } else if (trigger == 'Home') {\n // Home key.\n next = menuItems[0];\n\n } else if (trigger == 'End') {\n // End key.\n next = menuItems[menuItems.length - 1];\n }\n\n // Variable next is set if we do want to act on the keypress.\n if (next) {\n e.preventDefault();\n shiftFocus(next);\n }\n return;\n }\n });\n\n // Trap focus if the dropdown is a dialog.\n $(document).on('shown.bs.dropdown', e => {\n const dialog = e.target.querySelector('.dropdown-menu[role=\"dialog\"]');\n if (dialog) {\n // Use setTimeout to make sure the dialog is positioned correctly to prevent random scrolling.\n setTimeout(() => {\n FocusLockManager.trapFocus(dialog);\n });\n }\n });\n\n // Untrap focus when the dialog dropdown is closed.\n $(document).on('hidden.bs.dropdown', e => {\n const dialog = e.target.querySelector('.dropdown-menu[role=\"dialog\"]');\n if (dialog) {\n FocusLockManager.untrapFocus();\n }\n\n // We need to focus on the menu trigger.\n const trigger = e.target.querySelector('[data-toggle=\"dropdown\"]');\n // If it's a click event, then no element is focused because the clicked element is inside a closed dropdown.\n const focused = e.clickEvent?.target || (document.activeElement !== document.body ? document.activeElement : null);\n if (trigger && focused && e.target.contains(focused)) {\n shiftFocus(trigger, () => {\n if (document.activeElement === document.body) {\n // If the focus is currently on the body, then we can safely assume that the focus needs to be updated.\n return true;\n }\n\n // If the focus is on a child of the clicked element still, then update the focus.\n return e.target.contains(document.activeElement);\n });\n }\n });\n};\n\n/**\n * A lot of Bootstrap's out of the box features don't work if dropdown items are not focusable.\n */\nconst comboboxFix = () => {\n $(document).on('show.bs.dropdown', e => {\n if (e.relatedTarget.matches('[role=\"combobox\"]')) {\n const combobox = e.relatedTarget;\n const listbox = document.querySelector(`#${combobox.getAttribute('aria-controls')}[role=\"listbox\"]`);\n\n if (listbox) {\n const selectedOption = listbox.querySelector('[role=\"option\"][aria-selected=\"true\"]');\n\n // To make sure ArrowDown doesn't move the active option afterwards.\n setTimeout(() => {\n if (selectedOption) {\n selectedOption.classList.add('active');\n combobox.setAttribute('aria-activedescendant', selectedOption.id);\n } else {\n const firstOption = listbox.querySelector('[role=\"option\"]');\n firstOption.setAttribute('aria-selected', 'true');\n firstOption.classList.add('active');\n combobox.setAttribute('aria-activedescendant', firstOption.id);\n }\n }, 0);\n }\n }\n });\n\n $(document).on('hidden.bs.dropdown', e => {\n if (e.relatedTarget.matches('[role=\"combobox\"]')) {\n const combobox = e.relatedTarget;\n const listbox = document.querySelector(`#${combobox.getAttribute('aria-controls')}[role=\"listbox\"]`);\n\n combobox.removeAttribute('aria-activedescendant');\n\n if (listbox) {\n setTimeout(() => {\n // Undo all previously highlighted options.\n listbox.querySelectorAll('.active[role=\"option\"]').forEach(option => {\n option.classList.remove('active');\n });\n }, 0);\n }\n }\n });\n\n // Handling keyboard events for both navigating through and selecting options.\n document.addEventListener('keydown', e => {\n if (e.target.matches('[role=\"combobox\"][aria-controls]:not([aria-haspopup=dialog])')) {\n const combobox = e.target;\n const trigger = e.key;\n let next = null;\n const listbox = document.querySelector(`#${combobox.getAttribute('aria-controls')}[role=\"listbox\"]`);\n const options = listbox.querySelectorAll('[role=\"option\"]');\n const activeOption = listbox.querySelector('.active[role=\"option\"]');\n const editable = combobox.hasAttribute('aria-autocomplete');\n\n // Under the special case that the dropdown menu is being shown as a result of the key press (like when the user\n // presses ArrowDown or Enter or ... to open the dropdown menu), activeOption is not set yet.\n // It's because of a race condition with show.bs.dropdown event handler.\n if (options && (activeOption || editable)) {\n if (trigger == 'ArrowDown') {\n for (let i = 0; i < options.length - 1; i++) {\n if (options[i] == activeOption) {\n next = options[i + 1];\n break;\n }\n }\n if (editable && !next) {\n next = options[0];\n }\n } if (trigger == 'ArrowUp') {\n for (let i = 1; i < options.length; i++) {\n if (options[i] == activeOption) {\n next = options[i - 1];\n break;\n }\n }\n if (editable && !next) {\n next = options[options.length - 1];\n }\n } else if (trigger == 'Home' && !editable) {\n next = options[0];\n } else if (trigger == 'End' && !editable) {\n next = options[options.length - 1];\n } else if ((trigger == ' ' && !editable) || trigger == 'Enter') {\n e.preventDefault();\n selectOption(combobox, activeOption);\n } else if (!editable) {\n // Search for options by finding the first option that has\n // text starting with the typed character (case insensitive).\n for (let i = 0; i < options.length; i++) {\n const option = options[i];\n const optionText = option.textContent.trim().toLowerCase();\n const keyPressed = e.key.toLowerCase();\n if (optionText.indexOf(keyPressed) == 0) {\n next = option;\n break;\n }\n }\n }\n\n // Variable next is set if we do want to act on the keypress.\n if (next) {\n e.preventDefault();\n if (activeOption) {\n activeOption.classList.remove('active');\n }\n next.classList.add('active');\n combobox.setAttribute('aria-activedescendant', next.id);\n next.scrollIntoView({block: 'nearest'});\n }\n }\n }\n });\n\n document.addEventListener('click', e => {\n const option = e.target.closest('[role=\"listbox\"] [role=\"option\"]');\n if (option) {\n const listbox = option.closest('[role=\"listbox\"]');\n const combobox = document.querySelector(`[role=\"combobox\"][aria-controls=\"${listbox.id}\"]`);\n if (combobox) {\n selectOption(combobox, option);\n }\n }\n });\n\n // In case some code somewhere else changes the value of the combobox.\n document.addEventListener('change', e => {\n if (e.target.matches('input[type=\"hidden\"][id]')) {\n const combobox = document.querySelector(`[role=\"combobox\"][data-input-element=\"${e.target.id}\"]`);\n const option = e.target.parentElement.querySelector(`[role=\"option\"][data-value=\"${e.target.value}\"]`);\n\n if (combobox && option) {\n selectOption(combobox, option);\n }\n }\n });\n\n const selectOption = (combobox, option) => {\n const listbox = option.closest('[role=\"listbox\"]');\n const oldSelectedOption = listbox.querySelector('[role=\"option\"][aria-selected=\"true\"]');\n\n if (oldSelectedOption != option) {\n if (oldSelectedOption) {\n oldSelectedOption.removeAttribute('aria-selected');\n }\n option.setAttribute('aria-selected', 'true');\n }\n\n if (combobox.hasAttribute('value')) {\n combobox.value = option.dataset.shortText || option.textContent.replace(/[\\n\\r]+|[\\s]{2,}/g, ' ').trim();\n } else {\n const selectedOptionContainer = combobox.querySelector('[data-selected-option]');\n if (selectedOptionContainer) {\n selectedOptionContainer.textContent = option.dataset.shortText || option.textContent;\n } else {\n combobox.textContent = option.dataset.shortText || option.textContent;\n }\n }\n\n if (combobox.dataset.inputElement) {\n const inputElement = document.getElementById(combobox.dataset.inputElement);\n if (inputElement && (inputElement.value != option.dataset.value)) {\n inputElement.value = option.dataset.value;\n inputElement.dispatchEvent(new Event('change', {bubbles: true}));\n }\n }\n };\n};\n\n/**\n * After page load, focus on any element with special autofocus attribute.\n */\nconst autoFocus = () => {\n window.addEventListener(\"load\", () => {\n const alerts = document.querySelectorAll('[data-aria-autofocus=\"true\"][role=\"alert\"]');\n Array.prototype.forEach.call(alerts, autofocusElement => {\n // According to the specification an role=\"alert\" region is only read out on change to the content\n // of that region.\n autofocusElement.innerHTML += ' ';\n autofocusElement.removeAttribute('data-aria-autofocus');\n });\n });\n};\n\n/**\n * Changes the focus to the correct element based on the key that is pressed.\n * @param {NodeList} elements A NodeList of focusable elements to navigate between.\n * @param {KeyboardEvent} e The keyboard event that triggers the roving focus.\n * @param {boolean} vertical Whether the navigation is vertical.\n * @param {boolean} updateTabIndex Whether to update the tabIndex of the elements.\n */\nconst rovingFocus = (elements, e, vertical, updateTabIndex) => {\n const rtl = window.right_to_left();\n const arrowNext = vertical ? 'ArrowDown' : (rtl ? 'ArrowLeft' : 'ArrowRight');\n const arrowPrevious = vertical ? 'ArrowUp' : (rtl ? 'ArrowRight' : 'ArrowLeft');\n const keys = [arrowNext, arrowPrevious, 'Home', 'End'];\n\n if (!keys.includes(e.key)) {\n return;\n }\n\n const focusElement = index => {\n elements[index].focus();\n if (updateTabIndex) {\n elements.forEach((element, i) => element.setAttribute('tabindex', i === index ? '0' : '-1'));\n }\n };\n\n const currentIndex = Array.prototype.indexOf.call(elements, e.target);\n let nextIndex;\n\n switch (e.key) {\n case arrowNext:\n e.preventDefault();\n nextIndex = (currentIndex + 1 < elements.length) ? currentIndex + 1 : 0;\n focusElement(nextIndex);\n break;\n case arrowPrevious:\n e.preventDefault();\n nextIndex = (currentIndex - 1 >= 0) ? currentIndex - 1 : elements.length - 1;\n focusElement(nextIndex);\n break;\n case 'Home':\n e.preventDefault();\n focusElement(0);\n break;\n case 'End':\n e.preventDefault();\n focusElement(elements.length - 1);\n }\n};\n\n/**\n * Fix accessibility issues regarding tab elements focus and their tab order in Bootstrap navs.\n */\nconst tabElementFix = () => {\n document.addEventListener('keydown', e => {\n if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) {\n if (e.target.matches('[role=\"tablist\"] [role=\"tab\"]')) {\n const tabList = e.target.closest('[role=\"tablist\"]');\n const tabs = Array.prototype.filter.call(\n tabList.querySelectorAll('[role=\"tab\"]'),\n tab => !!tab.offsetHeight\n ); // We only work with the visible tabs.\n const vertical = tabList.getAttribute('aria-orientation') == 'vertical';\n\n rovingFocus(tabs, e, vertical, false);\n }\n }\n });\n\n document.addEventListener('click', e => {\n if (e.target.matches('[role=\"tablist\"] [data-toggle=\"tab\"], [role=\"tablist\"] [data-toggle=\"pill\"]')) {\n const tabs = e.target.closest('[role=\"tablist\"]').querySelectorAll('[data-toggle=\"tab\"], [data-toggle=\"pill\"]');\n e.preventDefault();\n $(e.target).tab('show');\n tabs.forEach(tab => {\n tab.tabIndex = -1;\n });\n e.target.tabIndex = 0;\n }\n });\n};\n\n/**\n * Fix keyboard interaction with Bootstrap Collapse elements.\n *\n * @see {@link https://www.w3.org/TR/wai-aria-practices-1.1/#disclosure|WAI-ARIA Authoring Practices 1.1 - Disclosure (Show/Hide)}\n */\nconst collapseFix = () => {\n document.addEventListener('keydown', e => {\n if (e.target.matches('[data-toggle=\"collapse\"]')) {\n // Pressing space should toggle expand/collapse.\n if (e.key === ' ') {\n e.preventDefault();\n e.target.click();\n }\n }\n });\n};\n\n/**\n * Fix accessibility issues\n */\nconst toolbarFix = () => {\n document.addEventListener('keydown', e => {\n if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) {\n if (e.target.matches('[role=\"toolbar\"] button')) {\n const buttons = e.target.closest('[role=\"toolbar\"]').querySelectorAll('button');\n rovingFocus(buttons, e, false, true);\n }\n }\n });\n};\n\nexport const init = () => {\n dropdownFix();\n comboboxFix();\n autoFocus();\n tabElementFix();\n collapseFix();\n toolbarFix();\n};\n"],"names":["dropdownFix","focusEnd","setFocusEnd","end","shiftFocus","element","focusCheck","pendingPromise","Pending","setTimeout","focus","resolve","handleMenuButton","e","trigger","key","fixFocus","preventDefault","target","click","menu","parentElement","querySelector","menuItems","foundMenuItem","querySelectorAll","length","result","getFocusEnd","document","addEventListener","matches","closest","toLowerCase","i","item","text","trim","indexOf","next","on","dialog","FocusLockManager","trapFocus","untrapFocus","focused","clickEvent","activeElement","body","contains","rovingFocus","elements","vertical","updateTabIndex","rtl","window","right_to_left","arrowNext","arrowPrevious","includes","focusElement","index","forEach","setAttribute","currentIndex","Array","prototype","call","nextIndex","relatedTarget","combobox","listbox","getAttribute","selectedOption","classList","add","id","firstOption","removeAttribute","option","remove","options","activeOption","editable","hasAttribute","selectOption","optionText","textContent","keyPressed","scrollIntoView","block","value","oldSelectedOption","dataset","shortText","replace","selectedOptionContainer","inputElement","getElementById","dispatchEvent","Event","bubbles","comboboxFix","alerts","autofocusElement","innerHTML","tabList","tabs","filter","tab","offsetHeight","tabIndex","buttons"],"mappings":";;;;;;;01BA8BMA,YAAc,SACZC,UAAW,QACTC,YAAc,eAACC,+DACjBF,SAAWE,KASTC,WAAa,SAACC,aAASC,kEAAa,WAChCC,eAAiB,IAAIC,iBAAQ,2BACnCC,YAAW,KACFH,aAAcA,cACfD,QAAQK,QAGZH,eAAeI,YAChB,KAIDC,iBAAmBC,UACfC,QAAUD,EAAEE,QACdC,UAAW,KAGC,MAAZF,SAA+B,UAAZA,UACnBE,UAAW,EAEXH,EAAEI,iBAEFJ,EAAEK,OAAOC,SAIG,YAAZL,SAAqC,cAAZA,UACzBE,UAAW,IAGVA,sBAMCI,KAAOP,EAAEK,OAAOG,cAAcC,cAAc,qBAC9CC,WAAY,EACZC,eAAgB,EAEhBJ,OACAG,UAAYH,KAAKK,iBAAiB,sBAElCF,WAAaA,UAAUG,OAAS,IAEhB,YAAZZ,QACAZ,cAEAA,aAAY,GAIZsB,cA3DQ,YACVG,OAAS1B,gBACfA,UAAW,EACJ0B,QAuDCC,GACgBL,UAAUA,UAAUG,OAAS,GAG7BH,UAAU,IAI9BC,eACApB,WAAWoB,gBAMnBK,SAASC,iBAAiB,YAAYjB,OAC9BA,EAAEK,OAAOa,QAAQ,mCAAoC,OAC/CX,KAAOP,EAAEK,OAAOc,QAAQ,qBACzBZ,kBAGCG,UAAYH,KAAKK,iBAAiB,yBACnCF,uBAICT,QAAUD,EAAEE,IAAIkB,kBAEjB,IAAIC,EAAI,EAAGA,EAAIX,UAAUG,OAAQQ,IAAK,OACjCC,KAAOZ,UAAUW,MAEU,GADhBC,KAAKC,KAAKC,OAAOJ,cACrBK,QAAQxB,SAAe,CAChCV,WAAW+B,kBAQ3BN,SAASC,iBAAiB,WAAWjB,OAI7BA,EAAEK,OAAOa,QAAQ,6BACjBnB,iBAAiBC,GAGjBA,EAAEK,OAAOa,QAAQ,0CACXjB,QAAUD,EAAEE,QACdwB,MAAO,QACLnB,KAAOP,EAAEK,OAAOc,QAAQ,qBAEzBZ,kBAGCG,UAAYH,KAAKK,iBAAiB,yBACnCF,oBAIU,aAAXT,QAAwB,KACnB,IAAIoB,EAAI,EAAGA,EAAIX,UAAUG,OAAS,EAAGQ,OAClCX,UAAUW,IAAMrB,EAAEK,OAAQ,CAC1BqB,KAAOhB,UAAUW,EAAI,SAIxBK,OAEDA,KAAOhB,UAAU,SAElB,GAAe,WAAXT,QAAsB,KAExB,IAAIoB,EAAI,EAAGA,EAAIX,UAAUG,OAAQQ,OAC9BX,UAAUW,IAAMrB,EAAEK,OAAQ,CAC1BqB,KAAOhB,UAAUW,EAAI,SAIxBK,OAEDA,KAAOhB,UAAUA,UAAUG,OAAS,QAEtB,QAAXZ,QAEPyB,KAAOhB,UAAU,GAEC,OAAXT,UAEPyB,KAAOhB,UAAUA,UAAUG,OAAS,IAIpCa,OACA1B,EAAEI,iBACFb,WAAWmC,oCAOrBV,UAAUW,GAAG,qBAAqB3B,UAC1B4B,OAAS5B,EAAEK,OAAOI,cAAc,iCAClCmB,QAEAhC,YAAW,KACPiC,iBAAiBC,UAAUF,kCAMrCZ,UAAUW,GAAG,sBAAsB3B,sBAClBA,EAAEK,OAAOI,cAAc,kCAElCoB,iBAAiBE,oBAIf9B,QAAUD,EAAEK,OAAOI,cAAc,4BAEjCuB,+BAAUhC,EAAEiC,yDAAY5B,UAAWW,SAASkB,gBAAkBlB,SAASmB,KAAOnB,SAASkB,cAAgB,MACzGjC,SAAW+B,SAAWhC,EAAEK,OAAO+B,SAASJ,UACxCzC,WAAWU,SAAS,IACZe,SAASkB,gBAAkBlB,SAASmB,MAMjCnC,EAAEK,OAAO+B,SAASpB,SAASkB,qBAuM5CG,YAAc,CAACC,SAAUtC,EAAGuC,SAAUC,wBAClCC,IAAMC,OAAOC,gBACbC,UAAYL,SAAW,YAAeE,IAAM,YAAc,aAC1DI,cAAgBN,SAAW,UAAaE,IAAM,aAAe,gBACtD,CAACG,UAAWC,cAAe,OAAQ,OAEtCC,SAAS9C,EAAEE,kBAIf6C,aAAeC,QACjBV,SAASU,OAAOnD,QACZ2C,gBACAF,SAASW,SAAQ,CAACzD,QAAS6B,IAAM7B,QAAQ0D,aAAa,WAAY7B,IAAM2B,MAAQ,IAAM,SAIxFG,aAAeC,MAAMC,UAAU5B,QAAQ6B,KAAKhB,SAAUtC,EAAEK,YAC1DkD,iBAEIvD,EAAEE,UACD0C,UACD5C,EAAEI,iBACFmD,UAAaJ,aAAe,EAAIb,SAASzB,OAAUsC,aAAe,EAAI,EACtEJ,aAAaQ,sBAEZV,cACD7C,EAAEI,iBACFmD,UAAaJ,aAAe,GAAK,EAAKA,aAAe,EAAIb,SAASzB,OAAS,EAC3EkC,aAAaQ,qBAEZ,OACDvD,EAAEI,iBACF2C,aAAa,aAEZ,MACD/C,EAAEI,iBACF2C,aAAaT,SAASzB,OAAS,mBAmEvB,KAChB1B,cAvSgB,0BACd6B,UAAUW,GAAG,oBAAoB3B,OAC3BA,EAAEwD,cAActC,QAAQ,qBAAsB,OACxCuC,SAAWzD,EAAEwD,cACbE,QAAU1C,SAASP,yBAAkBgD,SAASE,aAAa,yCAE7DD,QAAS,OACHE,eAAiBF,QAAQjD,cAAc,yCAG7Cb,YAAW,QACHgE,eACAA,eAAeC,UAAUC,IAAI,UAC7BL,SAASP,aAAa,wBAAyBU,eAAeG,QAC3D,OACGC,YAAcN,QAAQjD,cAAc,mBAC1CuD,YAAYd,aAAa,gBAAiB,QAC1Cc,YAAYH,UAAUC,IAAI,UAC1BL,SAASP,aAAa,wBAAyBc,YAAYD,OAEhE,4BAKb/C,UAAUW,GAAG,sBAAsB3B,OAC7BA,EAAEwD,cAActC,QAAQ,qBAAsB,OACxCuC,SAAWzD,EAAEwD,cACbE,QAAU1C,SAASP,yBAAkBgD,SAASE,aAAa,sCAEjEF,SAASQ,gBAAgB,yBAErBP,SACA9D,YAAW,KAEP8D,QAAQ9C,iBAAiB,0BAA0BqC,SAAQiB,SACvDA,OAAOL,UAAUM,OAAO,eAE7B,OAMfnD,SAASC,iBAAiB,WAAWjB,OAC7BA,EAAEK,OAAOa,QAAQ,gEAAiE,OAC5EuC,SAAWzD,EAAEK,OACbJ,QAAUD,EAAEE,QACdwB,KAAO,WACLgC,QAAU1C,SAASP,yBAAkBgD,SAASE,aAAa,sCAC3DS,QAAUV,QAAQ9C,iBAAiB,mBACnCyD,aAAeX,QAAQjD,cAAc,0BACrC6D,SAAWb,SAASc,aAAa,wBAKnCH,UAAYC,cAAgBC,UAAW,IACxB,aAAXrE,QAAwB,KACnB,IAAIoB,EAAI,EAAGA,EAAI+C,QAAQvD,OAAS,EAAGQ,OAChC+C,QAAQ/C,IAAMgD,aAAc,CAC5B3C,KAAO0C,QAAQ/C,EAAI,SAIvBiD,WAAa5C,OACbA,KAAO0C,QAAQ,OAEN,WAAXnE,QAAsB,KACnB,IAAIoB,EAAI,EAAGA,EAAI+C,QAAQvD,OAAQQ,OAC5B+C,QAAQ/C,IAAMgD,aAAc,CAC5B3C,KAAO0C,QAAQ/C,EAAI,SAIvBiD,WAAa5C,OACbA,KAAO0C,QAAQA,QAAQvD,OAAS,SAEjC,GAAe,QAAXZ,SAAsBqE,SAE1B,GAAe,OAAXrE,SAAqBqE,UAEzB,GAAgB,KAAXrE,UAAmBqE,UAAwB,SAAXrE,QACxCD,EAAEI,iBACFoE,aAAaf,SAAUY,mBACpB,IAAKC,aAGH,IAAIjD,EAAI,EAAGA,EAAI+C,QAAQvD,OAAQQ,IAAK,OAC/B6C,OAASE,QAAQ/C,GACjBoD,WAAaP,OAAOQ,YAAYlD,OAAOJ,cACvCuD,WAAa3E,EAAEE,IAAIkB,iBACa,GAAlCqD,WAAWhD,QAAQkD,YAAkB,CACrCjD,KAAOwC,oBAZfxC,KAAO0C,QAAQA,QAAQvD,OAAS,QAFhCa,KAAO0C,QAAQ,GAqBf1C,OACA1B,EAAEI,iBACEiE,cACAA,aAAaR,UAAUM,OAAO,UAElCzC,KAAKmC,UAAUC,IAAI,UACnBL,SAASP,aAAa,wBAAyBxB,KAAKqC,IACpDrC,KAAKkD,eAAe,CAACC,MAAO,kBAM5C7D,SAASC,iBAAiB,SAASjB,UACzBkE,OAASlE,EAAEK,OAAOc,QAAQ,uCAC5B+C,OAAQ,OACFR,QAAUQ,OAAO/C,QAAQ,oBACzBsC,SAAWzC,SAASP,yDAAkDiD,QAAQK,UAChFN,UACAe,aAAaf,SAAUS,YAMnClD,SAASC,iBAAiB,UAAUjB,OAC5BA,EAAEK,OAAOa,QAAQ,4BAA6B,OACxCuC,SAAWzC,SAASP,8DAAuDT,EAAEK,OAAO0D,UACpFG,OAASlE,EAAEK,OAAOG,cAAcC,oDAA6CT,EAAEK,OAAOyE,aAExFrB,UAAYS,QACZM,aAAaf,SAAUS,kBAK7BM,aAAe,CAACf,SAAUS,gBAEtBa,kBADUb,OAAO/C,QAAQ,oBACGV,cAAc,4CAE5CsE,mBAAqBb,SACjBa,mBACAA,kBAAkBd,gBAAgB,iBAEtCC,OAAOhB,aAAa,gBAAiB,SAGrCO,SAASc,aAAa,SACtBd,SAASqB,MAAQZ,OAAOc,QAAQC,WAAaf,OAAOQ,YAAYQ,QAAQ,oBAAqB,KAAK1D,WAC/F,OACG2D,wBAA0B1B,SAAShD,cAAc,0BACnD0E,wBACAA,wBAAwBT,YAAcR,OAAOc,QAAQC,WAAaf,OAAOQ,YAEzEjB,SAASiB,YAAcR,OAAOc,QAAQC,WAAaf,OAAOQ,eAI9DjB,SAASuB,QAAQI,aAAc,OACzBA,aAAepE,SAASqE,eAAe5B,SAASuB,QAAQI,cAC1DA,cAAiBA,aAAaN,OAASZ,OAAOc,QAAQF,QACtDM,aAAaN,MAAQZ,OAAOc,QAAQF,MACpCM,aAAaE,cAAc,IAAIC,MAAM,SAAU,CAACC,SAAS,SAsIrEC,GA5HA/C,OAAOzB,iBAAiB,QAAQ,WACtByE,OAAS1E,SAASJ,iBAAiB,8CACzCwC,MAAMC,UAAUJ,QAAQK,KAAKoC,QAAQC,mBAGjCA,iBAAiBC,WAAa,IAC9BD,iBAAiB1B,gBAAgB,6BAyDzCjD,SAASC,iBAAiB,WAAWjB,OAC7B,CAAC,UAAW,YAAa,YAAa,aAAc,OAAQ,OAAO8C,SAAS9C,EAAEE,MAC1EF,EAAEK,OAAOa,QAAQ,iCAAkC,OAC7C2E,QAAU7F,EAAEK,OAAOc,QAAQ,oBAC3B2E,KAAO1C,MAAMC,UAAU0C,OAAOzC,KAChCuC,QAAQjF,iBAAiB,iBACzBoF,OAASA,IAAIC,eAEX1D,SAAuD,YAA5CsD,QAAQlC,aAAa,oBAEtCtB,YAAYyD,KAAM9F,EAAGuC,UAAU,OAK3CvB,SAASC,iBAAiB,SAASjB,OAC3BA,EAAEK,OAAOa,QAAQ,+EAAgF,OAC3F4E,KAAO9F,EAAEK,OAAOc,QAAQ,oBAAoBP,iBAAiB,6CACnEZ,EAAEI,qCACAJ,EAAEK,QAAQ2F,IAAI,QAChBF,KAAK7C,SAAQ+C,MACTA,IAAIE,UAAY,KAEpBlG,EAAEK,OAAO6F,SAAW,MAW5BlF,SAASC,iBAAiB,WAAWjB,IAC7BA,EAAEK,OAAOa,QAAQ,6BAEH,MAAVlB,EAAEE,MACFF,EAAEI,iBACFJ,EAAEK,OAAOC,YAUrBU,SAASC,iBAAiB,WAAWjB,OAC7B,CAAC,UAAW,YAAa,YAAa,aAAc,OAAQ,OAAO8C,SAAS9C,EAAEE,MAC1EF,EAAEK,OAAOa,QAAQ,2BAA4B,OACvCiF,QAAUnG,EAAEK,OAAOc,QAAQ,oBAAoBP,iBAAiB,UACtEyB,YAAY8D,QAASnG,GAAG,GAAO"} \ No newline at end of file diff --git a/theme/boost/amd/src/aria.js b/theme/boost/amd/src/aria.js index 860d190dada..0b41237c716 100644 --- a/theme/boost/amd/src/aria.js +++ b/theme/boost/amd/src/aria.js @@ -416,47 +416,50 @@ const autoFocus = () => { }; /** - * Changes the focus to the correct tab based on the key that is pressed. - * @param {KeyboardEvent} e + * Changes the focus to the correct element based on the key that is pressed. + * @param {NodeList} elements A NodeList of focusable elements to navigate between. + * @param {KeyboardEvent} e The keyboard event that triggers the roving focus. + * @param {boolean} vertical Whether the navigation is vertical. + * @param {boolean} updateTabIndex Whether to update the tabIndex of the elements. */ -const updateTabFocus = e => { - const tabList = e.target.closest('[role="tablist"]'); - const vertical = tabList.getAttribute('aria-orientation') == 'vertical'; +const rovingFocus = (elements, e, vertical, updateTabIndex) => { const rtl = window.right_to_left(); const arrowNext = vertical ? 'ArrowDown' : (rtl ? 'ArrowLeft' : 'ArrowRight'); const arrowPrevious = vertical ? 'ArrowUp' : (rtl ? 'ArrowRight' : 'ArrowLeft'); - const tabs = Array.prototype.filter.call( - tabList.querySelectorAll('[role="tab"]'), - tab => !!tab.offsetHeight); // We only work with the visible tabs. + const keys = [arrowNext, arrowPrevious, 'Home', 'End']; - for (let i = 0; i < tabs.length; i++) { - tabs[i].index = i; + if (!keys.includes(e.key)) { + return; } + const focusElement = index => { + elements[index].focus(); + if (updateTabIndex) { + elements.forEach((element, i) => element.setAttribute('tabindex', i === index ? '0' : '-1')); + } + }; + + const currentIndex = Array.prototype.indexOf.call(elements, e.target); + let nextIndex; + switch (e.key) { case arrowNext: e.preventDefault(); - if (e.target.index !== undefined && tabs[e.target.index + 1]) { - tabs[e.target.index + 1].focus(); - } else { - tabs[0].focus(); - } + nextIndex = (currentIndex + 1 < elements.length) ? currentIndex + 1 : 0; + focusElement(nextIndex); break; case arrowPrevious: e.preventDefault(); - if (e.target.index !== undefined && tabs[e.target.index - 1]) { - tabs[e.target.index - 1].focus(); - } else { - tabs[tabs.length - 1].focus(); - } + nextIndex = (currentIndex - 1 >= 0) ? currentIndex - 1 : elements.length - 1; + focusElement(nextIndex); break; case 'Home': e.preventDefault(); - tabs[0].focus(); + focusElement(0); break; case 'End': e.preventDefault(); - tabs[tabs.length - 1].focus(); + focusElement(elements.length - 1); } }; @@ -467,7 +470,14 @@ const tabElementFix = () => { document.addEventListener('keydown', e => { if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) { if (e.target.matches('[role="tablist"] [role="tab"]')) { - updateTabFocus(e); + const tabList = e.target.closest('[role="tablist"]'); + const tabs = Array.prototype.filter.call( + tabList.querySelectorAll('[role="tab"]'), + tab => !!tab.offsetHeight + ); // We only work with the visible tabs. + const vertical = tabList.getAttribute('aria-orientation') == 'vertical'; + + rovingFocus(tabs, e, vertical, false); } } }); @@ -502,10 +512,25 @@ const collapseFix = () => { }); }; +/** + * Fix accessibility issues + */ +const toolbarFix = () => { + document.addEventListener('keydown', e => { + if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) { + if (e.target.matches('[role="toolbar"] button')) { + const buttons = e.target.closest('[role="toolbar"]').querySelectorAll('button'); + rovingFocus(buttons, e, false, true); + } + } + }); +}; + export const init = () => { dropdownFix(); comboboxFix(); autoFocus(); tabElementFix(); collapseFix(); + toolbarFix(); };