Merge branch 'MDL-80750-main' of https://github.com/mihailges/moodle
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
issueNumber: MDL-80750
|
||||
notes:
|
||||
mod_assign:
|
||||
- message: >
|
||||
A new method named `get_grading_batch_operation_details` has been added
|
||||
to the `assign_feedback_plugin` abstract class. Assignment feedback
|
||||
plugins can now override this method to define bulk action buttons that
|
||||
will appear in the sticky footer on the assignment grading page.
|
||||
type: improved
|
||||
- message: >
|
||||
The `assign_feedback_plugin::get_grading_batch_operations` method is now
|
||||
deprecated. Use
|
||||
`assign_feedback_plugin::get_grading_batch_operation_details` instead.
|
||||
type: deprecated
|
||||
- message: >
|
||||
The `assign_grading_table::plugingradingbatchoperations` property is
|
||||
removed. You can use
|
||||
`assign_feedback_plugin::get_grading_batch_operation_details` instead.
|
||||
type: deprecated
|
||||
@@ -6,6 +6,6 @@ define("core_grades/bulkactions/edit/tree/bulk_actions",["exports","core/bulkact
|
||||
* @copyright 2023 Mihail Geshoski <mihail@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
const Selectors_selectBulkItemCheckbox='input[type="checkbox"].itemselect';class GradebookEditTreeBulkActions extends _bulk_actions.default{static init(courseID){return new this(courseID)}constructor(courseID){var obj,key,value;super(),value=null,(key="courseID")in(obj=this)?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,this.courseID=courseID}getBulkActions(){return[new _move.default(this.courseID)]}getSelectedItems(){return document.querySelectorAll("".concat(Selectors_selectBulkItemCheckbox,":checked"))}registerItemSelectChangeEvent(eventHandler){document.querySelectorAll(Selectors_selectBulkItemCheckbox).forEach((checkbox=>{checkbox.addEventListener("change",eventHandler.bind(this))}))}}return _exports.default=GradebookEditTreeBulkActions,_exports.default}));
|
||||
const Selectors_selectBulkItemCheckbox='input[type="checkbox"].itemselect';class GradebookEditTreeBulkActions extends _bulk_actions.default{static init(courseID){return new this(courseID)}constructor(courseID){var obj,key,value;super(),value=null,(key="courseID")in(obj=this)?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,this.courseID=courseID}getBulkActions(){return[new _move.default(this.courseID)]}getSelectedItems(){return document.querySelectorAll("".concat(Selectors_selectBulkItemCheckbox,":checked"))}registerItemSelectChangeEvent(eventHandler){document.querySelectorAll(Selectors_selectBulkItemCheckbox).forEach((checkbox=>{checkbox.addEventListener("change",eventHandler.bind(this))}))}deselectItem(selectedItem){selectedItem.checked=!1}}return _exports.default=GradebookEditTreeBulkActions,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=bulk_actions.min.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"bulk_actions.min.js","sources":["../../../../src/bulkactions/edit/tree/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 <http://www.gnu.org/licenses/>.\n\nimport BulkActions from \"core/bulkactions/bulk_actions\";\nimport GradebookEditTreeBulkMove from \"core_grades/bulkactions/edit/tree/move\";\n\n/**\n * Class for defining the bulk actions area in the gradebook setup page.\n *\n * @module core_grades/bulkactions/edit/tree/bulk_actions\n * @copyright 2023 Mihail Geshoski <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"].itemselect'\n};\n\nexport default class GradebookEditTreeBulkActions extends BulkActions {\n\n /** @property {int|null} courseID The course ID. */\n courseID = null;\n\n /**\n * Returns the instance of the class.\n *\n * @param {int} courseID\n * @returns {GradebookEditTreeBulkActions}\n */\n static init(courseID) {\n return new this(courseID);\n }\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 * Returns the array of the relevant bulk action objects for the gradebook setup page.\n *\n * @method getBulkActions\n * @returns {Array}\n */\n getBulkActions() {\n return [\n new GradebookEditTreeBulkMove(this.courseID)\n ];\n }\n\n /**\n * Returns the array of selected items.\n *\n * @method getSelectedItems\n * @returns {Array}\n */\n getSelectedItems() {\n return document.querySelectorAll(`${Selectors.selectBulkItemCheckbox}:checked`);\n }\n\n /**\n * Adds the listener for the item select change event.\n *\n * @method registerItemSelectChangeEvent\n * @param {function} eventHandler The event handler function.\n * @returns {void}\n */\n registerItemSelectChangeEvent(eventHandler) {\n const itemSelectCheckboxes = document.querySelectorAll(Selectors.selectBulkItemCheckbox);\n itemSelectCheckboxes.forEach((checkbox) => {\n checkbox.addEventListener('change', eventHandler.bind(this));\n });\n }\n}\n"],"names":["Selectors","GradebookEditTreeBulkActions","BulkActions","courseID","this","constructor","getBulkActions","GradebookEditTreeBulkMove","getSelectedItems","document","querySelectorAll","registerItemSelectChangeEvent","eventHandler","forEach","checkbox","addEventListener","bind"],"mappings":";;;;;;;;MA0BMA,iCACsB,0CAGPC,qCAAqCC,kCAW1CC,iBACD,IAAIC,KAAKD,UASpBE,YAAYF,0CAlBD,6IAoBFA,SAAWA,SASpBG,uBACW,CACH,IAAIC,cAA0BH,KAAKD,WAU3CK,0BACWC,SAASC,2BAAoBV,8CAUxCW,8BAA8BC,cACGH,SAASC,iBAAiBV,kCAClCa,SAASC,WAC1BA,SAASC,iBAAiB,SAAUH,aAAaI,KAAKZ"}
|
||||
{"version":3,"file":"bulk_actions.min.js","sources":["../../../../src/bulkactions/edit/tree/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 <http://www.gnu.org/licenses/>.\n\nimport BulkActions from \"core/bulkactions/bulk_actions\";\nimport GradebookEditTreeBulkMove from \"core_grades/bulkactions/edit/tree/move\";\n\n/**\n * Class for defining the bulk actions area in the gradebook setup page.\n *\n * @module core_grades/bulkactions/edit/tree/bulk_actions\n * @copyright 2023 Mihail Geshoski <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst Selectors = {\n selectBulkItemCheckbox: 'input[type=\"checkbox\"].itemselect'\n};\n\nexport default class GradebookEditTreeBulkActions extends BulkActions {\n\n /** @property {int|null} courseID The course ID. */\n courseID = null;\n\n /**\n * Returns the instance of the class.\n *\n * @param {int} courseID\n * @returns {GradebookEditTreeBulkActions}\n */\n static init(courseID) {\n return new this(courseID);\n }\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 * Returns the array of the relevant bulk action objects for the gradebook setup page.\n *\n * @method getBulkActions\n * @returns {Array}\n */\n getBulkActions() {\n return [\n new GradebookEditTreeBulkMove(this.courseID)\n ];\n }\n\n /**\n * Returns the array of selected items.\n *\n * @method getSelectedItems\n * @returns {Array}\n */\n getSelectedItems() {\n return document.querySelectorAll(`${Selectors.selectBulkItemCheckbox}:checked`);\n }\n\n /**\n * Adds the listener for the item select change event.\n *\n * @method registerItemSelectChangeEvent\n * @param {function} eventHandler The event handler function.\n * @returns {void}\n */\n registerItemSelectChangeEvent(eventHandler) {\n const itemSelectCheckboxes = document.querySelectorAll(Selectors.selectBulkItemCheckbox);\n itemSelectCheckboxes.forEach((checkbox) => {\n checkbox.addEventListener('change', eventHandler.bind(this));\n });\n }\n\n /**\n * Defines the action for deselecting a selected item.\n *\n * @method deselectItem\n * @param {HTMLElement} selectedItem The selected element.\n * @returns {void}\n */\n deselectItem(selectedItem) {\n selectedItem.checked = false;\n }\n}\n"],"names":["Selectors","GradebookEditTreeBulkActions","BulkActions","courseID","this","constructor","getBulkActions","GradebookEditTreeBulkMove","getSelectedItems","document","querySelectorAll","registerItemSelectChangeEvent","eventHandler","forEach","checkbox","addEventListener","bind","deselectItem","selectedItem","checked"],"mappings":";;;;;;;;MA0BMA,iCACsB,0CAGPC,qCAAqCC,kCAW1CC,iBACD,IAAIC,KAAKD,UASpBE,YAAYF,0CAlBD,6IAoBFA,SAAWA,SASpBG,uBACW,CACH,IAAIC,cAA0BH,KAAKD,WAU3CK,0BACWC,SAASC,2BAAoBV,8CAUxCW,8BAA8BC,cACGH,SAASC,iBAAiBV,kCAClCa,SAASC,WAC1BA,SAASC,iBAAiB,SAAUH,aAAaI,KAAKZ,UAW9Da,aAAaC,cACTA,aAAaC,SAAU"}
|
||||
+1
-1
@@ -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'button[data-action="move"]'}async triggerBulkAction(){const modal=await this.showModal();this.registerCustomListenerEvents(modal)}async renderBulkActionTrigger(){return _templates.default.render("core_grades/bulkactions/edit/tree/bulk_move_trigger",{})}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
|
||||
File diff suppressed because one or more lines are too long
@@ -89,4 +89,15 @@ export default class GradebookEditTreeBulkActions extends BulkActions {
|
||||
checkbox.addEventListener('change', eventHandler.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the action for deselecting a selected item.
|
||||
*
|
||||
* @method deselectItem
|
||||
* @param {HTMLElement} selectedItem The selected element.
|
||||
* @returns {void}
|
||||
*/
|
||||
deselectItem(selectedItem) {
|
||||
selectedItem.checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ export default class GradebookEditTreeBulkMove extends BulkAction {
|
||||
* @returns {string} The bulk move action trigger selector.
|
||||
*/
|
||||
getBulkActionTriggerSelector() {
|
||||
return 'button[data-action="move"]';
|
||||
return '[data-type="bulkactions"] [data-action="move"]';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,10 +82,15 @@ export default class GradebookEditTreeBulkMove extends BulkAction {
|
||||
* Renders the bulk move action trigger element.
|
||||
*
|
||||
* @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() {
|
||||
return Templates.render('core_grades/bulkactions/edit/tree/bulk_move_trigger', {});
|
||||
async renderBulkActionTrigger(showInDropdown, index) {
|
||||
return Templates.render('core_grades/bulkactions/edit/tree/bulk_move_trigger', {
|
||||
showindropdown: showInDropdown,
|
||||
isfirst: index === 0,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,7 +26,7 @@ Feature: Admin can set Recover grades default setting
|
||||
And I navigate to "Submissions" in current page administration
|
||||
And I click on "Quick grading" "checkbox"
|
||||
And I set the field "User grade" to "60.00"
|
||||
And I press "Save all quick grading changes"
|
||||
And I click on "Save" "button" in the "sticky-footer" "region"
|
||||
# Confirm that assigned grade was saved
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
And I should see "60.00" in the "Student One" "table_row"
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ define("core/bulkactions/bulk_action",["exports"],(function(_exports){Object.def
|
||||
* @copyright 2023 Mihail Geshoski <mihail@moodle.com>
|
||||
* @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() 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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.\n\n/**\n * Base class for defining a bulk action.\n *\n * @module core/bulkactions/bulk_action\n * @copyright 2023 Mihail Geshoski <[email protected]>\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 * @returns {Promise}\n */\n renderBulkActionTrigger() {\n throw new Error(`renderBulkActionTrigger() 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,OASnFC,gCACU,IAAIH,iEAA0DN,KAAKO,YAAYC"}
|
||||
{"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 <http://www.gnu.org/licenses/>.\n\n/**\n * Base class for defining a bulk action.\n *\n * @module core/bulkactions/bulk_action\n * @copyright 2023 Mihail Geshoski <[email protected]>\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"}
|
||||
+1
-1
@@ -5,6 +5,6 @@ define("core/bulkactions/bulk_actions",["exports","core/templates","core/str","c
|
||||
* @module core/bulkactions/bulk_actions
|
||||
* @copyright 2023 Mihail Geshoski <mihail@moodle.com>
|
||||
* @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(){if(_defineProperty(this,"initialStickyFooterContent",null),_defineProperty(this,"selectedItems",[]),_defineProperty(this,"isBulkActionsModeEnabled",!1),!this.getStickyFooterContainer())throw new Error("Sticky footer not found.");this.initialStickyFooterContent=this.getStickyFooterContainer().innerHTML,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(){let data={bulkselectioncount:this.selectedItems.length,actions:[]};return await Promise.all(this.getBulkActions().map((async bulkAction=>{data.actions.push({actiontrigger:await bulkAction.renderBulkActionTrigger()})}))),_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))}deselectItem(selectedItem){throw new Error("deselectItem(".concat(selectedItem,") 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=>{this.deselectItem(item)})),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
|
||||
File diff suppressed because one or more lines are too long
@@ -77,9 +77,11 @@ export default class BulkAction {
|
||||
* Renders the bulk action trigger element.
|
||||
*
|
||||
* @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() {
|
||||
throw new Error(`renderBulkActionTrigger() must be implemented in ${this.constructor.name}`);
|
||||
renderBulkActionTrigger(showInDropdown = false, index) {
|
||||
throw new Error(`renderBulkActionTrigger(${showInDropdown}, ${index}) must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,18 +45,29 @@ export default class BulkActions {
|
||||
/** @property {boolean} isBulkActionsModeEnabled Whether the bulk actions mode is enabled. */
|
||||
isBulkActionsModeEnabled = false;
|
||||
|
||||
/**
|
||||
* @property {int} maxButtons Sets the maximum number of action buttons to display. If exceeded, additional actions
|
||||
* are shown in a dropdown menu.
|
||||
*/
|
||||
maxButtons = 5;
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param {int|null} maxButtons Sets the maximum number of action buttons to display. If exceeded, additional actions
|
||||
* are shown in a dropdown menu.
|
||||
* @returns {void}
|
||||
*/
|
||||
constructor() {
|
||||
constructor(maxButtons = null) {
|
||||
if (!this.getStickyFooterContainer()) {
|
||||
throw new Error('Sticky footer not found.');
|
||||
}
|
||||
// Store any pre-existing content in the sticky footer. When bulk actions mode is enabled, this content will be
|
||||
// replaced with the bulk actions content and restored when bulk actions mode is disabled.
|
||||
this.initialStickyFooterContent = this.getStickyFooterContainer().innerHTML;
|
||||
if (maxButtons) {
|
||||
this.maxButtons = maxButtons;
|
||||
}
|
||||
// Register and handle the item select change event.
|
||||
this.registerItemSelectChangeEvent(async() => {
|
||||
this.selectedItems = this.getSelectedItems();
|
||||
@@ -105,6 +116,21 @@ export default class BulkActions {
|
||||
throw new Error(`registerItemSelectChangeEvent(${eventHandler}) must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the action for deselecting a selected item.
|
||||
*
|
||||
* The base bulk actions class supports deselecting all selected items but does not have knowledge of the type of the
|
||||
* selected element. Therefore, each subclass must explicitly define the action of resetting the attributes that
|
||||
* indicate a selected state.
|
||||
*
|
||||
* @method deselectItem
|
||||
* @param {HTMLElement} selectedItem The selected element.
|
||||
* @returns {void}
|
||||
*/
|
||||
deselectItem(selectedItem) {
|
||||
throw new Error(`deselectItem(${selectedItem}) must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sticky footer container.
|
||||
*
|
||||
@@ -119,7 +145,7 @@ export default class BulkActions {
|
||||
* Enables the bulk action mode.
|
||||
*
|
||||
* @method enableBulkActionsMode
|
||||
* @returns {Promise}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async enableBulkActionsMode() {
|
||||
// Make sure that the sticky footer is enabled.
|
||||
@@ -137,9 +163,9 @@ export default class BulkActions {
|
||||
// Register the click listener event for the cancel bulk mode button.
|
||||
bulkModeContainer.addEventListener('click', (e) => {
|
||||
if (e.target.closest(Selectors.cancelBulkActionModeElement)) {
|
||||
// Uncheck all selected items.
|
||||
// Deselect all selected items.
|
||||
this.selectedItems.forEach((item) => {
|
||||
item.checked = false;
|
||||
this.deselectItem(item);
|
||||
});
|
||||
// Disable the bulk action mode.
|
||||
this.disableBulkActionsMode();
|
||||
@@ -168,17 +194,38 @@ export default class BulkActions {
|
||||
* Renders the bulk actions content.
|
||||
*
|
||||
* @method renderBulkActions
|
||||
* @returns {Promise}
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async renderBulkActions() {
|
||||
let data = {
|
||||
'bulkselectioncount': this.selectedItems.length,
|
||||
'actions': []
|
||||
const data = {
|
||||
bulkselectioncount: this.selectedItems.length,
|
||||
actions: [],
|
||||
moreactions: [],
|
||||
hasmoreactions: false,
|
||||
};
|
||||
// Render the bulk actions trigger element for each available bulk action.
|
||||
await Promise.all(this.getBulkActions().map(async(bulkAction) => {
|
||||
data.actions.push({'actiontrigger': await bulkAction.renderBulkActionTrigger()});
|
||||
}));
|
||||
const bulkActions = this.getBulkActions();
|
||||
const showMoreButton = bulkActions.length > this.maxButtons;
|
||||
|
||||
// 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),
|
||||
index
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Separate rendered actions into data.actions and data.moreactions in the correct order.
|
||||
actions.forEach((actionTrigger, index) => {
|
||||
if (showMoreButton && (index >= this.maxButtons - 1)) {
|
||||
data.moreactions.push({'actiontrigger': actionTrigger});
|
||||
} else {
|
||||
data.actions.push({'actiontrigger': actionTrigger});
|
||||
}
|
||||
});
|
||||
|
||||
data.hasmoreactions = data.moreactions.length > 0;
|
||||
|
||||
return Templates.render('core/bulkactions/bulk_actions', data);
|
||||
}
|
||||
|
||||
@@ -1197,7 +1197,7 @@ class flexible_table {
|
||||
} else {
|
||||
// Print empty rows to fill the table to the current pagesize.
|
||||
// This is done so the header aria-controls attributes do not point to
|
||||
// non existant elements.
|
||||
// non-existent elements.
|
||||
$emptyrow = array_fill(0, count($this->columns), '');
|
||||
while ($this->currentrow < $this->pagesize) {
|
||||
$this->print_row($emptyrow, 'emptyrow');
|
||||
|
||||
@@ -20,18 +20,27 @@
|
||||
Renders a trigger element for a given bulk action.
|
||||
|
||||
Context variables required for this template:
|
||||
* none
|
||||
* 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,
|
||||
"isfirst": true
|
||||
}
|
||||
}}
|
||||
<button
|
||||
type="button"
|
||||
class="btn py-0 d-flex flex-column"
|
||||
data-action="{{$action}}{{/action}}"
|
||||
title="{{$title}}{{/title}}"
|
||||
>
|
||||
<span class="w-100 ps-2">{{$icon}}{{/icon}}</span>
|
||||
<span>{{$title}}{{/title}}</span>
|
||||
</button>
|
||||
{{#showindropdown}}
|
||||
<a class="dropdown-item" href="#" data-action="{{$action}}{{/action}}" role="menuitem">{{$title}}{{/title}}</a>
|
||||
{{/showindropdown}}
|
||||
{{^showindropdown}}
|
||||
<button
|
||||
type="button"
|
||||
class="btn py-0 d-flex flex-column"
|
||||
data-action="{{$action}}{{/action}}"
|
||||
title="{{$title}}{{/title}}"
|
||||
{{^isfirst}}tabindex="-1"{{/isfirst}}
|
||||
>
|
||||
<span class="w-100 ps-2">{{$icon}}{{/icon}}</span>
|
||||
<span>{{$title}}{{/title}}</span>
|
||||
</button>
|
||||
{{/showindropdown}}
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
Context variables required for this template:
|
||||
* actions - Array of objects with the following properties:
|
||||
* actiontrigger - The HTML for the action trigger.
|
||||
* hasmoreactions - Whether there are more actions than the ones displayed.
|
||||
* moreactions - Array of objects with the following properties:
|
||||
* actiontrigger - The HTML for the action trigger.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
@@ -29,6 +32,12 @@
|
||||
{
|
||||
"actiontrigger": "<button>Move</button>"
|
||||
}
|
||||
],
|
||||
"hasmoreactions": true,
|
||||
"moreactions": [
|
||||
{
|
||||
"actiontrigger": "<button>Delete</button>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
@@ -36,13 +45,34 @@
|
||||
<div class="d-flex">
|
||||
</div>
|
||||
<div data-for="bulktools">
|
||||
<ul class="actions nav" data-for="bulkactions">
|
||||
<div class="btn-toolbar" role="toolbar" aria-label="{{#str}} bulkactions, core {{/str}}" data-for="bulkactions">
|
||||
{{#actions}}
|
||||
<li class="nav-item">
|
||||
{{{actiontrigger}}}
|
||||
</li>
|
||||
{{{actiontrigger}}}
|
||||
{{/actions}}
|
||||
</ul>
|
||||
{{#hasmoreactions}}
|
||||
<div class="dropup">
|
||||
<button
|
||||
class="btn py-0 d-flex flex-column"
|
||||
type="button"
|
||||
id="more-actions-toggle-{{uniqid}}"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span class="w-100 pl-2">
|
||||
{{#pix}} i/menu, core {{/pix}}
|
||||
</span>
|
||||
<span>{{#str}} moremenu, core {{/str}}</span>
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="more-actions-toggle-{{uniqid}}" role="menu">
|
||||
{{#moreactions}}
|
||||
{{{actiontrigger}}}
|
||||
{{/moreactions}}
|
||||
</div>
|
||||
</div>
|
||||
{{/hasmoreactions}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<div class="ms-auto">
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
define("mod_assign/bulkactions/grading/delete",["exports","core/bulkactions/bulk_action","core/templates","core/str","core/modal_delete_cancel","core/modal_events"],(function(_exports,_bulk_action,_templates,_str,_modal_delete_cancel,_modal_events){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),_templates=_interopRequireDefault(_templates),_modal_delete_cancel=_interopRequireDefault(_modal_delete_cancel),_modal_events=_interopRequireDefault(_modal_events);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(){const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),modal=await _modal_delete_cancel.default.create({title:await(0,_str.getString)("removesubmission","mod_assign"),buttons:{save:await(0,_str.getString)("batchoperationremovesubmission","mod_assign")},body:_templates.default.render("mod_assign/bulkactions/grading/bulk_action_modal_body",{text:await(0,_str.getString)("batchoperationconfirmremovesubmission","mod_assign"),operation:"removesubmission",cmid:_classPrivateFieldGet(this,_cmid),selectedusers:selectedUsers.join(","),sesskey:_classPrivateFieldGet(this,_sesskey)}),show:!0,removeOnClose:!0});modal.getRoot().on(_modal_events.default.delete,(e=>{e.preventDefault(),modal.getRoot().find("form").submit()}))}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
|
||||
@@ -0,0 +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 <http://www.gnu.org/licenses/>.\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 <[email protected]>\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 {getString} from 'core/str';\nimport DeleteCancelModal from 'core/modal_delete_cancel';\nimport ModalEvents from 'core/modal_events';\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 const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n\n const modal = await DeleteCancelModal.create({\n title: await getString('removesubmission', 'mod_assign'),\n buttons: {\n save: await getString('batchoperationremovesubmission', 'mod_assign'),\n },\n body: Templates.render('mod_assign/bulkactions/grading/bulk_action_modal_body', {\n text: await getString('batchoperationconfirmremovesubmission', 'mod_assign'),\n operation: 'removesubmission',\n cmid: this.#cmid,\n selectedusers: selectedUsers.join(','),\n sesskey: this.#sesskey\n }),\n show: true,\n removeOnClose: true,\n });\n\n // Handle delete event.\n modal.getRoot().on(ModalEvents.delete, (e) => {\n e.preventDefault();\n modal.getRoot().find('form').submit();\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","selectedUsers","document","querySelectorAll","map","checkbox","value","modal","DeleteCancelModal","create","title","buttons","save","body","Templates","render","text","operation","this","selectedusers","join","show","removeOnClose","getRoot","on","ModalEvents","delete","e","preventDefault","find","submit","showInDropdown","index","showindropdown","isfirst"],"mappings":"uoDA6BMA,iCACsB,yHAGCC,qBAazBC,YAAYC,KAAMC,yLAEDD,0CACGC,SAGpBC,qCACW,6FAIDC,cAAgB,IAAIC,SAASC,iBAAiBR,mCAAmCS,KAAIC,UAAYA,SAASC,QAE1GC,YAAcC,6BAAkBC,OAAO,CACzCC,YAAa,kBAAU,mBAAoB,cAC3CC,QAAS,CACLC,WAAY,kBAAU,iCAAkC,eAE5DC,KAAMC,mBAAUC,OAAO,wDAAyD,CAC5EC,WAAY,kBAAU,wCAAyC,cAC/DC,UAAW,mBACXnB,2BAAMoB,YACNC,cAAelB,cAAcmB,KAAK,KAClCrB,8BAASmB,iBAEbG,MAAM,EACNC,eAAe,IAInBf,MAAMgB,UAAUC,GAAGC,sBAAYC,QAASC,IACpCA,EAAEC,iBACFrB,MAAMgB,UAAUM,KAAK,QAAQC,0CAIPC,eAAgBC,cACnClB,mBAAUC,OAAO,qDAAsD,CAC1EkB,eAAgBF,eAChBG,QAAmB,IAAVF"}
|
||||
@@ -0,0 +1,3 @@
|
||||
define("mod_assign/bulkactions/grading/extend",["exports","core/bulkactions/bulk_action","core/templates","core/str","core/modal_save_cancel","core/modal_events"],(function(_exports,_bulk_action,_templates,_str,_modal_save_cancel,_modal_events){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),_templates=_interopRequireDefault(_templates),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_modal_events=_interopRequireDefault(_modal_events);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="grantextension"]'}async triggerBulkAction(){const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),modal=await _modal_save_cancel.default.create({title:await(0,_str.getString)("grantextension","mod_assign"),buttons:{save:await(0,_str.getString)("batchoperationgrantextension","mod_assign")},body:_templates.default.render("mod_assign/bulkactions/grading/bulk_action_modal_body",{text:await(0,_str.getString)("batchoperationconfirmgrantextension","mod_assign"),operation:"grantextension",cmid:_classPrivateFieldGet(this,_cmid),selectedusers:selectedUsers.join(","),sesskey:_classPrivateFieldGet(this,_sesskey)}),show:!0,removeOnClose:!0});modal.getRoot().on(_modal_events.default.save,(e=>{e.preventDefault(),modal.getRoot().find("form").submit()}))}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
|
||||
@@ -0,0 +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 <http://www.gnu.org/licenses/>.\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 <[email protected]>\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 {getString} from 'core/str';\nimport SaveCancelModal from 'core/modal_save_cancel';\nimport ModalEvents from 'core/modal_events';\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=\"grantextension\"]';\n }\n\n async triggerBulkAction() {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n\n const modal = await SaveCancelModal.create({\n title: await getString('grantextension', 'mod_assign'),\n buttons: {\n save: await getString('batchoperationgrantextension', 'mod_assign'),\n },\n body: Templates.render('mod_assign/bulkactions/grading/bulk_action_modal_body', {\n text: await getString('batchoperationconfirmgrantextension', 'mod_assign'),\n operation: 'grantextension',\n cmid: this.#cmid,\n selectedusers: selectedUsers.join(','),\n sesskey: this.#sesskey\n }),\n show: true,\n removeOnClose: true,\n });\n\n // Handle save event.\n modal.getRoot().on(ModalEvents.save, (e) => {\n e.preventDefault();\n modal.getRoot().find('form').submit();\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","sesskey","getBulkActionTriggerSelector","selectedUsers","document","querySelectorAll","map","checkbox","value","modal","SaveCancelModal","create","title","buttons","save","body","Templates","render","text","operation","this","selectedusers","join","show","removeOnClose","getRoot","on","ModalEvents","e","preventDefault","find","submit","showInDropdown","index","showindropdown","isfirst"],"mappings":"+nDA6BMA,iCACsB,yHAGCC,qBAazBC,YAAYC,KAAMC,yLAEDD,0CACGC,SAGpBC,qCACW,2FAIDC,cAAgB,IAAIC,SAASC,iBAAiBR,mCAAmCS,KAAIC,UAAYA,SAASC,QAE1GC,YAAcC,2BAAgBC,OAAO,CACvCC,YAAa,kBAAU,iBAAkB,cACzCC,QAAS,CACLC,WAAY,kBAAU,+BAAgC,eAE1DC,KAAMC,mBAAUC,OAAO,wDAAyD,CAC5EC,WAAY,kBAAU,sCAAuC,cAC7DC,UAAW,iBACXnB,2BAAMoB,YACNC,cAAelB,cAAcmB,KAAK,KAClCrB,8BAASmB,iBAEbG,MAAM,EACNC,eAAe,IAInBf,MAAMgB,UAAUC,GAAGC,sBAAYb,MAAOc,IAClCA,EAAEC,iBACFpB,MAAMgB,UAAUK,KAAK,QAAQC,0CAIPC,eAAgBC,cACnCjB,mBAAUC,OAAO,qDAAsD,CAC1EiB,eAAgBF,eAChBG,QAAmB,IAAVF"}
|
||||
@@ -0,0 +1,3 @@
|
||||
define("mod_assign/bulkactions/grading/general_action",["exports","core/bulkactions/bulk_action","core/templates","core/modal_save_cancel","core/modal_events"],(function(_exports,_bulk_action,_templates,_modal_save_cancel,_modal_events){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),_templates=_interopRequireDefault(_templates),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_modal_events=_interopRequireDefault(_modal_events);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(){const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),modal=await _modal_save_cancel.default.create({title:await _classPrivateFieldGet(this,_confirmationTitle),buttons:{save:await _classPrivateFieldGet(this,_confirmationYes)},body:_templates.default.render("mod_assign/bulkactions/grading/bulk_action_modal_body",{text:await _classPrivateFieldGet(this,_confirmationQuestion),operation:this.actionKey,cmid:_classPrivateFieldGet(this,_cmid),selectedusers:selectedUsers.join(","),sesskey:_classPrivateFieldGet(this,_sesskey)}),show:!0,removeOnClose:!0});modal.getRoot().on(_modal_events.default.save,(e=>{e.preventDefault(),modal.getRoot().find("form").submit()}))}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
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
|
||||
define("mod_assign/bulkactions/grading/message",["exports","core/bulkactions/bulk_action","core/templates","core_message/message_send_bulk"],(function(_exports,_bulk_action,_templates,_message_send_bulk){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Bulk action for messaging users in the assignment grading page.
|
||||
*
|
||||
* @module mod_assign/bulkactions/grading/message
|
||||
* @copyright 2024 Shamim Rezaie <shamim@moodle.com>
|
||||
* @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,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
|
||||
@@ -0,0 +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 <http://www.gnu.org/licenses/>.\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 <[email protected]>\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,oDAGXC,0BACUC,cAAgB,IAAIC,SAASC,iBAAiBN,mCAAmCO,KAAIC,UAAYA,SAASC,yCAC/FL,6CAGSM,eAAgBC,cACnCC,mBAAUC,OAAO,sDAAuD,CAC3EC,eAAgBJ,eAChBK,QAAmB,IAAVJ"}
|
||||
@@ -0,0 +1,3 @@
|
||||
define("mod_assign/bulkactions/grading/setmarkingallocation",["exports","core/bulkactions/bulk_action","core/templates","core/str","core/modal_save_cancel","core/modal_events"],(function(_exports,_bulk_action,_templates,_str,_modal_save_cancel,_modal_events){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),_templates=_interopRequireDefault(_templates),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_modal_events=_interopRequireDefault(_modal_events);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="setmarkingallocation"]'}async triggerBulkAction(){const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),modal=await _modal_save_cancel.default.create({title:await(0,_str.getString)("setmarkingallocation","mod_assign"),buttons:{save:await(0,_str.getString)("batchoperationsetmarkingallocation","mod_assign")},body:_templates.default.render("mod_assign/bulkactions/grading/bulk_action_modal_body",{text:await(0,_str.getString)("batchoperationconfirmsetmarkingallocation","mod_assign"),operation:"setmarkingallocation",cmid:_classPrivateFieldGet(this,_cmid),selectedusers:selectedUsers.join(","),sesskey:_classPrivateFieldGet(this,_sesskey)}),show:!0,removeOnClose:!0});modal.getRoot().on(_modal_events.default.save,(e=>{e.preventDefault(),modal.getRoot().find("form").submit()}))}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
|
||||
@@ -0,0 +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 <http://www.gnu.org/licenses/>.\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 <[email protected]>\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 {getString} from 'core/str';\nimport SaveCancelModal from 'core/modal_save_cancel';\nimport ModalEvents from 'core/modal_events';\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=\"setmarkingallocation\"]';\n }\n\n async triggerBulkAction() {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n\n const modal = await SaveCancelModal.create({\n title: await getString('setmarkingallocation', 'mod_assign'),\n buttons: {\n save: await getString('batchoperationsetmarkingallocation', 'mod_assign'),\n },\n body: Templates.render('mod_assign/bulkactions/grading/bulk_action_modal_body', {\n text: await getString('batchoperationconfirmsetmarkingallocation', 'mod_assign'),\n operation: 'setmarkingallocation',\n cmid: this.#cmid,\n selectedusers: selectedUsers.join(','),\n sesskey: this.#sesskey\n }),\n show: true,\n removeOnClose: true,\n });\n\n // Handle save event.\n modal.getRoot().on(ModalEvents.save, (e) => {\n e.preventDefault();\n modal.getRoot().find('form').submit();\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","sesskey","getBulkActionTriggerSelector","selectedUsers","document","querySelectorAll","map","checkbox","value","modal","SaveCancelModal","create","title","buttons","save","body","Templates","render","text","operation","this","selectedusers","join","show","removeOnClose","getRoot","on","ModalEvents","e","preventDefault","find","submit","showInDropdown","index","showindropdown","isfirst"],"mappings":"6oDA6BMA,iCACsB,yHAGCC,qBAazBC,YAAYC,KAAMC,yLAEDD,0CACGC,SAGpBC,qCACW,iGAIDC,cAAgB,IAAIC,SAASC,iBAAiBR,mCAAmCS,KAAIC,UAAYA,SAASC,QAE1GC,YAAcC,2BAAgBC,OAAO,CACvCC,YAAa,kBAAU,uBAAwB,cAC/CC,QAAS,CACLC,WAAY,kBAAU,qCAAsC,eAEhEC,KAAMC,mBAAUC,OAAO,wDAAyD,CAC5EC,WAAY,kBAAU,4CAA6C,cACnEC,UAAW,uBACXnB,2BAAMoB,YACNC,cAAelB,cAAcmB,KAAK,KAClCrB,8BAASmB,iBAEbG,MAAM,EACNC,eAAe,IAInBf,MAAMgB,UAAUC,GAAGC,sBAAYb,MAAOc,IAClCA,EAAEC,iBACFpB,MAAMgB,UAAUK,KAAK,QAAQC,0CAIPC,eAAgBC,cACnCjB,mBAAUC,OAAO,mEAAoE,CACxFiB,eAAgBF,eAChBG,QAAmB,IAAVF"}
|
||||
@@ -0,0 +1,3 @@
|
||||
define("mod_assign/bulkactions/grading/setmarkingworkflowstate",["exports","core/bulkactions/bulk_action","core/templates","core/str","core/modal_save_cancel","core/modal_events"],(function(_exports,_bulk_action,_templates,_str,_modal_save_cancel,_modal_events){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),_templates=_interopRequireDefault(_templates),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_modal_events=_interopRequireDefault(_modal_events);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="setmarkingworkflowstate"]'}async triggerBulkAction(){const selectedUsers=[...document.querySelectorAll(Selectors_selectBulkItemCheckbox)].map((checkbox=>checkbox.value)),modal=await _modal_save_cancel.default.create({title:await(0,_str.getString)("setmarkingworkflowstate","mod_assign"),buttons:{save:await(0,_str.getString)("batchoperationsetmarkingworkflowstate","mod_assign")},body:_templates.default.render("mod_assign/bulkactions/grading/bulk_action_modal_body",{text:await(0,_str.getString)("batchoperationconfirmsetmarkingworkflowstate","mod_assign"),operation:"setmarkingworkflowstate",cmid:_classPrivateFieldGet(this,_cmid),selectedusers:selectedUsers.join(","),sesskey:_classPrivateFieldGet(this,_sesskey)}),show:!0,removeOnClose:!0});modal.getRoot().on(_modal_events.default.save,(e=>{e.preventDefault(),modal.getRoot().find("form").submit()}))}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
|
||||
@@ -0,0 +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 <http://www.gnu.org/licenses/>.\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 <[email protected]>\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 {getString} from 'core/str';\nimport SaveCancelModal from 'core/modal_save_cancel';\nimport ModalEvents from 'core/modal_events';\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=\"setmarkingworkflowstate\"]';\n }\n\n async triggerBulkAction() {\n const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);\n\n const modal = await SaveCancelModal.create({\n title: await getString('setmarkingworkflowstate', 'mod_assign'),\n buttons: {\n save: await getString('batchoperationsetmarkingworkflowstate', 'mod_assign'),\n },\n body: Templates.render('mod_assign/bulkactions/grading/bulk_action_modal_body', {\n text: await getString('batchoperationconfirmsetmarkingworkflowstate', 'mod_assign'),\n operation: 'setmarkingworkflowstate',\n cmid: this.#cmid,\n selectedusers: selectedUsers.join(','),\n sesskey: this.#sesskey\n }),\n show: true,\n removeOnClose: true,\n });\n\n // Handle save event.\n modal.getRoot().on(ModalEvents.save, (e) => {\n e.preventDefault();\n modal.getRoot().find('form').submit();\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","sesskey","getBulkActionTriggerSelector","selectedUsers","document","querySelectorAll","map","checkbox","value","modal","SaveCancelModal","create","title","buttons","save","body","Templates","render","text","operation","this","selectedusers","join","show","removeOnClose","getRoot","on","ModalEvents","e","preventDefault","find","submit","showInDropdown","index","showindropdown","isfirst"],"mappings":"gpDA6BMA,iCACsB,yHAGCC,qBAazBC,YAAYC,KAAMC,yLAEDD,0CACGC,SAGpBC,qCACW,oGAIDC,cAAgB,IAAIC,SAASC,iBAAiBR,mCAAmCS,KAAIC,UAAYA,SAASC,QAE1GC,YAAcC,2BAAgBC,OAAO,CACvCC,YAAa,kBAAU,0BAA2B,cAClDC,QAAS,CACLC,WAAY,kBAAU,wCAAyC,eAEnEC,KAAMC,mBAAUC,OAAO,wDAAyD,CAC5EC,WAAY,kBAAU,+CAAgD,cACtEC,UAAW,0BACXnB,2BAAMoB,YACNC,cAAelB,cAAcmB,KAAK,KAClCrB,8BAASmB,iBAEbG,MAAM,EACNC,eAAe,IAInBf,MAAMgB,UAAUC,GAAGC,sBAAYb,MAAOc,IAClCA,EAAEC,iBACFpB,MAAMgB,UAAUK,KAAK,QAAQC,0CAIPC,eAAgBC,cACnCjB,mBAAUC,OAAO,sEAAuE,CAC3FiB,eAAgBF,eAChBG,QAAmB,IAAVF"}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
define("mod_assign/quick_grading",["exports","core_form/submit"],(function(_exports,formSubmit){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,formSubmit=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}
|
||||
/**
|
||||
* Module for the quick grading functionality on the submissions page.
|
||||
*
|
||||
* @module mod_assign/quick_grading
|
||||
* @copyright 2024 Mihail Geshoski <mihail@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/(formSubmit);const Selectors_quickGradingSaveRegion='[data-region="quick-grading-save"]',Selectors_notifyStudentsCheckbox='input[type="checkbox"][name="sendstudentnotifications"]',Selectors_notifyStudentsHidden='input[type="hidden"][name="sendstudentnotifications"]',Selectors_saveButton='button[type="submit"]';_exports.init=()=>{const quickGradingSaveRegion=document.querySelector(Selectors_quickGradingSaveRegion);if(quickGradingSaveRegion){const quickGradingSaveButton=quickGradingSaveRegion.querySelector(Selectors_saveButton);formSubmit.init(quickGradingSaveButton),quickGradingSaveRegion.addEventListener("change",(e=>{const notifyStudentsCheckbox=e.target.closest(Selectors_notifyStudentsCheckbox);if(notifyStudentsCheckbox){notifyStudentsCheckbox.parentNode.querySelector(Selectors_notifyStudentsHidden).disabled=notifyStudentsCheckbox.checked}}))}}}));
|
||||
|
||||
//# sourceMappingURL=quick_grading.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"quick_grading.min.js","sources":["../src/quick_grading.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 <http://www.gnu.org/licenses/>.\n\nimport * as formSubmit from 'core_form/submit';\n\n/**\n * Module for the quick grading functionality on the submissions page.\n *\n * @module mod_assign/quick_grading\n * @copyright 2024 Mihail Geshoski <[email protected]>\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 quickGradingSaveRegion: '[data-region=\"quick-grading-save\"]',\n notifyStudentsCheckbox: 'input[type=\"checkbox\"][name=\"sendstudentnotifications\"]',\n notifyStudentsHidden: 'input[type=\"hidden\"][name=\"sendstudentnotifications\"]',\n saveButton: 'button[type=\"submit\"]'\n};\n\n/**\n * Initialize module.\n */\nexport const init = () => {\n const quickGradingSaveRegion = document.querySelector(Selectors.quickGradingSaveRegion);\n if (quickGradingSaveRegion) {\n const quickGradingSaveButton = quickGradingSaveRegion.querySelector(Selectors.saveButton);\n // Initialize the submit button.\n formSubmit.init(quickGradingSaveButton);\n // Add 'change' event listener to the quick grading save region.\n quickGradingSaveRegion.addEventListener('change', e => {\n const notifyStudentsCheckbox = e.target.closest(Selectors.notifyStudentsCheckbox);\n // The target is the 'Notify student' checkbox.\n if (notifyStudentsCheckbox) {\n // The 'Notify student' option uses a hidden input and a checkbox. The hidden input is used to submit '0'\n // as a workaround when the checkbox is unchecked since unchecked checkboxes are not submitted with the\n // form. Therefore, we need to enable or disable the hidden input based on the checkbox state.\n const notifyStudentsHidden = notifyStudentsCheckbox.parentNode.querySelector(Selectors.notifyStudentsHidden);\n notifyStudentsHidden.disabled = notifyStudentsCheckbox.checked;\n }\n });\n }\n};\n"],"names":["Selectors","quickGradingSaveRegion","document","querySelector","quickGradingSaveButton","formSubmit","init","addEventListener","e","notifyStudentsCheckbox","target","closest","parentNode","disabled","checked"],"mappings":";;;;;;;wBA0BMA,iCACsB,qCADtBA,iCAEsB,0DAFtBA,+BAGoB,wDAHpBA,qBAIU,sCAMI,WACVC,uBAAyBC,SAASC,cAAcH,qCAClDC,uBAAwB,OAClBG,uBAAyBH,uBAAuBE,cAAcH,sBAEpEK,WAAWC,KAAKF,wBAEhBH,uBAAuBM,iBAAiB,UAAUC,UACxCC,uBAAyBD,EAAEE,OAAOC,QAAQX,qCAE5CS,uBAAwB,CAIKA,uBAAuBG,WAAWT,cAAcH,gCACxDa,SAAWJ,uBAAuBK"}
|
||||
@@ -0,0 +1,238 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class for defining the bulk actions area in the assignment grading page.
|
||||
*
|
||||
* @module mod_assign/bulkactions/grading/bulk_actions
|
||||
* @copyright 2024 Shamim Rezaie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import BulkActions from 'core/bulkactions/bulk_actions';
|
||||
import GeneralAction from './general_action';
|
||||
import DeleteAction from './delete';
|
||||
import ExtendAction from './extend';
|
||||
import MessageAction from './message';
|
||||
import SetMarkingAllocationAction from './setmarkingallocation';
|
||||
import SetMarkingWorkflowStateAction from './setmarkingworkflowstate';
|
||||
import Templates from 'core/templates';
|
||||
import {getString} from 'core/str';
|
||||
|
||||
const Selectors = {
|
||||
selectBulkItemCheckbox: 'input[type="checkbox"][name="selectedusers"]',
|
||||
selectBulkItemTrigger: 'input[type="checkbox"][name="selectedusers"], input[type="checkbox"][name="selectall"]',
|
||||
};
|
||||
|
||||
export default class extends BulkActions {
|
||||
/** @type {number} The course module ID. */
|
||||
#cmid;
|
||||
|
||||
/** @type {boolean} Whether to show the extend action. */
|
||||
#extend;
|
||||
|
||||
/** @type {boolean} Whether to show the grant extension action. */
|
||||
#grantAttempt;
|
||||
|
||||
/** @type {boolean} Whether to show the set marking allocation action. */
|
||||
#markingAllocation;
|
||||
|
||||
/** @type {string} Whether to show the message action. */
|
||||
#message;
|
||||
|
||||
/** @type {Array} The list of plugin operations. */
|
||||
#pluginOperations;
|
||||
|
||||
/** @type {boolean} Whether to show the remove submission action. */
|
||||
#removeSubmission;
|
||||
|
||||
/** @type {string} The session key. */
|
||||
#sesskey;
|
||||
|
||||
/** @type {boolean} Whether to show the revert to draft action. */
|
||||
#submissionDrafts;
|
||||
|
||||
/** @type {boolean} Whether to show the set workflow state action. */
|
||||
#workflowState;
|
||||
|
||||
/**
|
||||
* Returns the instance of the class.
|
||||
*
|
||||
* @param {Object} options - The options object.
|
||||
* @param {number} options.cmid - The course module ID.
|
||||
* @param {string} options.message - Whether to show the message action.
|
||||
* @param {boolean} options.submissiondrafts - Whether to show the revert to draft action.
|
||||
* @param {boolean} options.removesubmission - Whether to show the remove submission action.
|
||||
* @param {boolean} options.extend - Whether to show the grant extension action.
|
||||
* @param {boolean} options.grantattempt - Whether to show the grant attempt action.
|
||||
* @param {boolean} options.workflowstate - Whether to show the set workflow state action.
|
||||
* @param {boolean} options.markingallocation - Whether to show the set marking allocation action.
|
||||
* @param {Array} options.pluginoperations - The list of plugin operations.
|
||||
* @param {string} options.sesskey - The session key.
|
||||
* @returns {this} An instance of the anonymous class extending BulkActions.
|
||||
*/
|
||||
static init(options) {
|
||||
return new this(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* The class constructor
|
||||
*
|
||||
* @param {Object} options - The options object.
|
||||
* @param {number} options.cmid - The course module ID.
|
||||
* @param {string} options.message - Whether to show the message action.
|
||||
* @param {boolean} options.submissiondrafts - Whether to show the revert to draft action.
|
||||
* @param {boolean} options.removesubmission - Whether to show the remove submission action.
|
||||
* @param {boolean} options.extend - Whether to show the grant extension action.
|
||||
* @param {boolean} options.grantattempt - Whether to show the grant attempt action.
|
||||
* @param {boolean} options.workflowstate - Whether to show the set workflow state action.
|
||||
* @param {boolean} options.markingallocation - Whether to show the set marking allocation action.
|
||||
* @param {Array} options.pluginoperations - The list of plugin operations.
|
||||
* @param {string} options.sesskey - The session key.
|
||||
*/
|
||||
constructor({
|
||||
cmid, message, submissiondrafts, removesubmission, extend,
|
||||
grantattempt, workflowstate, markingallocation, pluginoperations, sesskey
|
||||
}) {
|
||||
super();
|
||||
this.#cmid = cmid;
|
||||
this.#message = message;
|
||||
this.#submissionDrafts = submissiondrafts;
|
||||
this.#removeSubmission = removesubmission;
|
||||
this.#extend = extend;
|
||||
this.#grantAttempt = grantattempt;
|
||||
this.#workflowState = workflowstate;
|
||||
this.#markingAllocation = markingallocation;
|
||||
this.#sesskey = sesskey;
|
||||
this.#pluginOperations = pluginoperations;
|
||||
}
|
||||
|
||||
getBulkActions() {
|
||||
const actions = [
|
||||
new GeneralAction(
|
||||
this.#cmid,
|
||||
this.#sesskey,
|
||||
'lock',
|
||||
getString('batchoperationlock', 'mod_assign'),
|
||||
Templates.renderPix('i/lock', 'core'),
|
||||
getString('locksubmissions', 'mod_assign'),
|
||||
getString('batchoperationconfirmlock', 'mod_assign'),
|
||||
getString('batchoperationlock', 'mod_assign'),
|
||||
),
|
||||
new GeneralAction(
|
||||
this.#cmid,
|
||||
this.#sesskey,
|
||||
'unlock',
|
||||
getString('batchoperationunlock', 'mod_assign'),
|
||||
Templates.renderPix('i/unlock', 'core'),
|
||||
getString('unlocksubmissions', 'mod_assign'),
|
||||
getString('batchoperationconfirmunlock', 'mod_assign'),
|
||||
getString('batchoperationunlock', 'mod_assign'),
|
||||
),
|
||||
new GeneralAction(
|
||||
this.#cmid,
|
||||
this.#sesskey,
|
||||
'downloadselected',
|
||||
getString('batchoperationdownloadselected', 'mod_assign'),
|
||||
Templates.renderPix('t/download', 'core'),
|
||||
getString('downloadselectedsubmissions', 'mod_assign'),
|
||||
getString('batchoperationconfirmdownloadselected', 'mod_assign'),
|
||||
getString('batchoperationdownloadselected', 'mod_assign'),
|
||||
),
|
||||
];
|
||||
|
||||
if (this.#removeSubmission) {
|
||||
actions.push(new DeleteAction(this.#cmid, this.#sesskey));
|
||||
}
|
||||
|
||||
if (this.#extend) {
|
||||
actions.push(new ExtendAction(this.#cmid, this.#sesskey));
|
||||
}
|
||||
|
||||
if (this.#grantAttempt) {
|
||||
actions.push(
|
||||
new GeneralAction(
|
||||
this.#cmid,
|
||||
this.#sesskey,
|
||||
'addattempt',
|
||||
getString('batchoperationaddattempt', 'mod_assign'),
|
||||
Templates.renderPix('t/add', 'core'),
|
||||
getString('addattempt', 'mod_assign'),
|
||||
getString('batchoperationconfirmaddattempt', 'mod_assign'),
|
||||
getString('batchoperationaddattempt', 'mod_assign'),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (this.#workflowState) {
|
||||
actions.push(new SetMarkingWorkflowStateAction(this.#cmid, this.#sesskey));
|
||||
}
|
||||
|
||||
if (this.#markingAllocation) {
|
||||
actions.push(new SetMarkingAllocationAction(this.#cmid, this.#sesskey));
|
||||
}
|
||||
|
||||
if (this.#submissionDrafts) {
|
||||
actions.push(
|
||||
new GeneralAction(
|
||||
this.#cmid,
|
||||
this.#sesskey,
|
||||
'reverttodraft',
|
||||
getString('batchoperationreverttodraft', 'mod_assign'),
|
||||
Templates.renderPix('e/undo', 'core'),
|
||||
getString('reverttodraft', 'mod_assign'),
|
||||
getString('batchoperationconfirmreverttodraft', 'mod_assign'),
|
||||
getString('batchoperationreverttodraft', 'mod_assign'),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (this.#message) {
|
||||
actions.push(new MessageAction());
|
||||
}
|
||||
|
||||
for (const operation of this.#pluginOperations) {
|
||||
actions.push(
|
||||
new GeneralAction(
|
||||
this.#cmid,
|
||||
this.#sesskey,
|
||||
operation.key,
|
||||
operation.label,
|
||||
operation.icon,
|
||||
operation.confirmationtitle,
|
||||
operation.confirmationquestion,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
getSelectedItems() {
|
||||
return document.querySelectorAll(`${Selectors.selectBulkItemCheckbox}:checked`);
|
||||
}
|
||||
|
||||
registerItemSelectChangeEvent(eventHandler) {
|
||||
const itemSelectCheckboxes = document.querySelectorAll(Selectors.selectBulkItemTrigger);
|
||||
itemSelectCheckboxes.forEach((checkbox) => {
|
||||
checkbox.addEventListener('change', eventHandler.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
deselectItem(selectedItem) {
|
||||
selectedItem.checked = false;
|
||||
selectedItem.closest('tr').classList.replace('selectedrow', 'unselectedrow');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class that defines the bulk action for removing submissions in the assignment grading page.
|
||||
*
|
||||
* @module mod_assign/bulkactions/grading/delete
|
||||
* @copyright 2024 Shamim Rezaie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import BulkAction from 'core/bulkactions/bulk_action';
|
||||
import Templates from 'core/templates';
|
||||
import {getString} from 'core/str';
|
||||
import DeleteCancelModal from 'core/modal_delete_cancel';
|
||||
import ModalEvents from 'core/modal_events';
|
||||
|
||||
const Selectors = {
|
||||
selectBulkItemCheckbox: 'input[type="checkbox"][name="selectedusers"]:checked',
|
||||
};
|
||||
|
||||
export default class extends BulkAction {
|
||||
/** @type {number} The course module ID. */
|
||||
#cmid;
|
||||
|
||||
/** @type {string} The session key. */
|
||||
#sesskey;
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param {number} cmid The course module ID.
|
||||
* @param {string} sesskey The session key.
|
||||
*/
|
||||
constructor(cmid, sesskey) {
|
||||
super();
|
||||
this.#cmid = cmid;
|
||||
this.#sesskey = sesskey;
|
||||
}
|
||||
|
||||
getBulkActionTriggerSelector() {
|
||||
return '[data-type="bulkactions"] [data-action="removesubmission"]';
|
||||
}
|
||||
|
||||
async triggerBulkAction() {
|
||||
const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);
|
||||
|
||||
const modal = await DeleteCancelModal.create({
|
||||
title: await getString('removesubmission', 'mod_assign'),
|
||||
buttons: {
|
||||
save: await getString('batchoperationremovesubmission', 'mod_assign'),
|
||||
},
|
||||
body: Templates.render('mod_assign/bulkactions/grading/bulk_action_modal_body', {
|
||||
text: await getString('batchoperationconfirmremovesubmission', 'mod_assign'),
|
||||
operation: 'removesubmission',
|
||||
cmid: this.#cmid,
|
||||
selectedusers: selectedUsers.join(','),
|
||||
sesskey: this.#sesskey
|
||||
}),
|
||||
show: true,
|
||||
removeOnClose: true,
|
||||
});
|
||||
|
||||
// Handle delete event.
|
||||
modal.getRoot().on(ModalEvents.delete, (e) => {
|
||||
e.preventDefault();
|
||||
modal.getRoot().find('form').submit();
|
||||
});
|
||||
}
|
||||
|
||||
async renderBulkActionTrigger(showInDropdown, index) {
|
||||
return Templates.render('mod_assign/bulkactions/grading/bulk_delete_trigger', {
|
||||
showindropdown: showInDropdown,
|
||||
isfirst: index === 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class that defines the bulk action to extend the assignment deadline in the assignment grading page.
|
||||
*
|
||||
* @module mod_assign/bulkactions/grading/extend
|
||||
* @copyright 2024 Shamim Rezaie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import BulkAction from 'core/bulkactions/bulk_action';
|
||||
import Templates from 'core/templates';
|
||||
import {getString} from 'core/str';
|
||||
import SaveCancelModal from 'core/modal_save_cancel';
|
||||
import ModalEvents from 'core/modal_events';
|
||||
|
||||
const Selectors = {
|
||||
selectBulkItemCheckbox: 'input[type="checkbox"][name="selectedusers"]:checked',
|
||||
};
|
||||
|
||||
export default class extends BulkAction {
|
||||
/** @type {number} The course module ID. */
|
||||
#cmid;
|
||||
|
||||
/** @type {string} The session key. */
|
||||
#sesskey;
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param {number} cmid The course module ID.
|
||||
* @param {string} sesskey The session key.
|
||||
*/
|
||||
constructor(cmid, sesskey) {
|
||||
super();
|
||||
this.#cmid = cmid;
|
||||
this.#sesskey = sesskey;
|
||||
}
|
||||
|
||||
getBulkActionTriggerSelector() {
|
||||
return '[data-type="bulkactions"] [data-action="grantextension"]';
|
||||
}
|
||||
|
||||
async triggerBulkAction() {
|
||||
const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);
|
||||
|
||||
const modal = await SaveCancelModal.create({
|
||||
title: await getString('grantextension', 'mod_assign'),
|
||||
buttons: {
|
||||
save: await getString('batchoperationgrantextension', 'mod_assign'),
|
||||
},
|
||||
body: Templates.render('mod_assign/bulkactions/grading/bulk_action_modal_body', {
|
||||
text: await getString('batchoperationconfirmgrantextension', 'mod_assign'),
|
||||
operation: 'grantextension',
|
||||
cmid: this.#cmid,
|
||||
selectedusers: selectedUsers.join(','),
|
||||
sesskey: this.#sesskey
|
||||
}),
|
||||
show: true,
|
||||
removeOnClose: true,
|
||||
});
|
||||
|
||||
// Handle save event.
|
||||
modal.getRoot().on(ModalEvents.save, (e) => {
|
||||
e.preventDefault();
|
||||
modal.getRoot().find('form').submit();
|
||||
});
|
||||
}
|
||||
|
||||
async renderBulkActionTrigger(showInDropdown, index) {
|
||||
return Templates.render('mod_assign/bulkactions/grading/bulk_extend_trigger', {
|
||||
showindropdown: showInDropdown,
|
||||
isfirst: index === 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class that defines the bulk action for general actions in the assignment grading page.
|
||||
*
|
||||
* @module mod_assign/bulkactions/grading/general_action
|
||||
* @copyright 2024 Shamim Rezaie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import BulkAction from 'core/bulkactions/bulk_action';
|
||||
import Templates from 'core/templates';
|
||||
import SaveCancelModal from 'core/modal_save_cancel';
|
||||
import ModalEvents from 'core/modal_events';
|
||||
|
||||
const Selectors = {
|
||||
selectBulkItemCheckbox: 'input[type="checkbox"][name="selectedusers"]:checked',
|
||||
};
|
||||
|
||||
export default class extends BulkAction {
|
||||
|
||||
/** @type {string} The action key. */
|
||||
actionKey;
|
||||
|
||||
/** @type {number} The course module ID. */
|
||||
#cmid;
|
||||
|
||||
/** @type {Promise<string>} The action button's icon. */
|
||||
#buttonIcon;
|
||||
|
||||
/** @type {Promise<string>} The action button's label. */
|
||||
#buttonLabel;
|
||||
|
||||
/** @type {Promise<string>} Title of the confirmation dialog. */
|
||||
#confirmationTitle;
|
||||
|
||||
/** @type {Promise<string>} Question of the confirmation dialog. */
|
||||
#confirmationQuestion;
|
||||
|
||||
/** @type {Promise<string>} Text for the confirmation yes button. */
|
||||
#confirmationYes;
|
||||
|
||||
/** @type {string} The session key. */
|
||||
#sesskey;
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param {int} cmid The course module ID.
|
||||
* @param {string} sesskey The session key.
|
||||
* @param {string} actionKey The action key.
|
||||
* @param {Promise<string>} buttonLabel The action button's label.
|
||||
* @param {Promise<string>} buttonIcon The action button's icon.
|
||||
* @param {Promise<string>} confirmationTitle Title of the confirmation dialog.
|
||||
* @param {Promise<string>} confirmationQuestion Question of the confirmation dialog.
|
||||
* @param {Promise<string>} confirmationYes Text for the confirmation yes button.
|
||||
*/
|
||||
constructor(cmid, sesskey, actionKey, buttonLabel, buttonIcon, confirmationTitle, confirmationQuestion, confirmationYes) {
|
||||
super();
|
||||
this.#cmid = cmid;
|
||||
this.#sesskey = sesskey;
|
||||
this.actionKey = actionKey;
|
||||
this.#buttonLabel = buttonLabel;
|
||||
this.#buttonIcon = buttonIcon;
|
||||
this.#confirmationTitle = confirmationTitle;
|
||||
this.#confirmationQuestion = confirmationQuestion;
|
||||
this.#confirmationYes = confirmationYes;
|
||||
}
|
||||
|
||||
getBulkActionTriggerSelector() {
|
||||
return `[data-type="bulkactions"] [data-action="${this.actionKey}"]`;
|
||||
}
|
||||
|
||||
async triggerBulkAction() {
|
||||
const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);
|
||||
|
||||
const modal = await SaveCancelModal.create({
|
||||
title: await this.#confirmationTitle,
|
||||
buttons: {
|
||||
save: await this.#confirmationYes,
|
||||
},
|
||||
body: Templates.render('mod_assign/bulkactions/grading/bulk_action_modal_body', {
|
||||
text: await this.#confirmationQuestion,
|
||||
operation: this.actionKey,
|
||||
cmid: this.#cmid,
|
||||
selectedusers: selectedUsers.join(','),
|
||||
sesskey: this.#sesskey
|
||||
}),
|
||||
show: true,
|
||||
removeOnClose: true,
|
||||
});
|
||||
|
||||
// Handle save event.
|
||||
modal.getRoot().on(ModalEvents.save, (e) => {
|
||||
e.preventDefault();
|
||||
modal.getRoot().find('form').submit();
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Bulk action for messaging users in the assignment grading page.
|
||||
*
|
||||
* @module mod_assign/bulkactions/grading/message
|
||||
* @copyright 2024 Shamim Rezaie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import BulkAction from 'core/bulkactions/bulk_action';
|
||||
import Templates from 'core/templates';
|
||||
import {showModal as showMessageModal} from 'core_message/message_send_bulk';
|
||||
|
||||
const Selectors = {
|
||||
selectBulkItemCheckbox: 'input[type="checkbox"][name="selectedusers"]:checked',
|
||||
};
|
||||
|
||||
export default class extends BulkAction {
|
||||
getBulkActionTriggerSelector() {
|
||||
return '[data-type="bulkactions"] [data-action="message"]';
|
||||
}
|
||||
|
||||
triggerBulkAction() {
|
||||
const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);
|
||||
showMessageModal(selectedUsers);
|
||||
}
|
||||
|
||||
async renderBulkActionTrigger(showInDropdown, index) {
|
||||
return Templates.render('mod_assign/bulkactions/grading/bulk_message_trigger', {
|
||||
showindropdown: showInDropdown,
|
||||
isfirst: index === 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Bulk action for allocating markers in the assignment grading page.
|
||||
*
|
||||
* @module mod_assign/bulkactions/grading/setmarkingallocation
|
||||
* @copyright 2024 Shamim Rezaie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import BulkAction from 'core/bulkactions/bulk_action';
|
||||
import Templates from 'core/templates';
|
||||
import {getString} from 'core/str';
|
||||
import SaveCancelModal from 'core/modal_save_cancel';
|
||||
import ModalEvents from 'core/modal_events';
|
||||
|
||||
const Selectors = {
|
||||
selectBulkItemCheckbox: 'input[type="checkbox"][name="selectedusers"]:checked',
|
||||
};
|
||||
|
||||
export default class extends BulkAction {
|
||||
/** @type {number} The course module ID. */
|
||||
#cmid;
|
||||
|
||||
/** @type {string} The session key. */
|
||||
#sesskey;
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param {number} cmid The course module ID.
|
||||
* @param {string} sesskey The session key.
|
||||
*/
|
||||
constructor(cmid, sesskey) {
|
||||
super();
|
||||
this.#cmid = cmid;
|
||||
this.#sesskey = sesskey;
|
||||
}
|
||||
|
||||
getBulkActionTriggerSelector() {
|
||||
return '[data-type="bulkactions"] [data-action="setmarkingallocation"]';
|
||||
}
|
||||
|
||||
async triggerBulkAction() {
|
||||
const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);
|
||||
|
||||
const modal = await SaveCancelModal.create({
|
||||
title: await getString('setmarkingallocation', 'mod_assign'),
|
||||
buttons: {
|
||||
save: await getString('batchoperationsetmarkingallocation', 'mod_assign'),
|
||||
},
|
||||
body: Templates.render('mod_assign/bulkactions/grading/bulk_action_modal_body', {
|
||||
text: await getString('batchoperationconfirmsetmarkingallocation', 'mod_assign'),
|
||||
operation: 'setmarkingallocation',
|
||||
cmid: this.#cmid,
|
||||
selectedusers: selectedUsers.join(','),
|
||||
sesskey: this.#sesskey
|
||||
}),
|
||||
show: true,
|
||||
removeOnClose: true,
|
||||
});
|
||||
|
||||
// Handle save event.
|
||||
modal.getRoot().on(ModalEvents.save, (e) => {
|
||||
e.preventDefault();
|
||||
modal.getRoot().find('form').submit();
|
||||
});
|
||||
}
|
||||
|
||||
async renderBulkActionTrigger(showInDropdown, index) {
|
||||
return Templates.render('mod_assign/bulkactions/grading/bulk_setmarkingallocation_trigger', {
|
||||
showindropdown: showInDropdown,
|
||||
isfirst: index === 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class that defines the bulk action for setting marking workflow state in the assignment grading page.
|
||||
*
|
||||
* @module mod_assign/bulkactions/grading/setmarkingworkflowstate
|
||||
* @copyright 2024 Shamim Rezaie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import BulkAction from 'core/bulkactions/bulk_action';
|
||||
import Templates from 'core/templates';
|
||||
import {getString} from 'core/str';
|
||||
import SaveCancelModal from 'core/modal_save_cancel';
|
||||
import ModalEvents from 'core/modal_events';
|
||||
|
||||
const Selectors = {
|
||||
selectBulkItemCheckbox: 'input[type="checkbox"][name="selectedusers"]:checked',
|
||||
};
|
||||
|
||||
export default class extends BulkAction {
|
||||
/** @type {number} The course module ID. */
|
||||
#cmid;
|
||||
|
||||
/** @type {string} The session key. */
|
||||
#sesskey;
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param {number} cmid The course module ID.
|
||||
* @param {string} sesskey The session key.
|
||||
*/
|
||||
constructor(cmid, sesskey) {
|
||||
super();
|
||||
this.#cmid = cmid;
|
||||
this.#sesskey = sesskey;
|
||||
}
|
||||
|
||||
getBulkActionTriggerSelector() {
|
||||
return '[data-type="bulkactions"] [data-action="setmarkingworkflowstate"]';
|
||||
}
|
||||
|
||||
async triggerBulkAction() {
|
||||
const selectedUsers = [...document.querySelectorAll(Selectors.selectBulkItemCheckbox)].map(checkbox => checkbox.value);
|
||||
|
||||
const modal = await SaveCancelModal.create({
|
||||
title: await getString('setmarkingworkflowstate', 'mod_assign'),
|
||||
buttons: {
|
||||
save: await getString('batchoperationsetmarkingworkflowstate', 'mod_assign'),
|
||||
},
|
||||
body: Templates.render('mod_assign/bulkactions/grading/bulk_action_modal_body', {
|
||||
text: await getString('batchoperationconfirmsetmarkingworkflowstate', 'mod_assign'),
|
||||
operation: 'setmarkingworkflowstate',
|
||||
cmid: this.#cmid,
|
||||
selectedusers: selectedUsers.join(','),
|
||||
sesskey: this.#sesskey
|
||||
}),
|
||||
show: true,
|
||||
removeOnClose: true,
|
||||
});
|
||||
|
||||
// Handle save event.
|
||||
modal.getRoot().on(ModalEvents.save, (e) => {
|
||||
e.preventDefault();
|
||||
modal.getRoot().find('form').submit();
|
||||
});
|
||||
}
|
||||
|
||||
async renderBulkActionTrigger(showInDropdown, index) {
|
||||
return Templates.render('mod_assign/bulkactions/grading/bulk_setmarkingworkflowstate_trigger', {
|
||||
showindropdown: showInDropdown,
|
||||
isfirst: index === 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import * as formSubmit from 'core_form/submit';
|
||||
|
||||
/**
|
||||
* Module for the quick grading functionality on the submissions page.
|
||||
*
|
||||
* @module mod_assign/quick_grading
|
||||
* @copyright 2024 Mihail Geshoski <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/** @constant {Object} The object containing the relevant selectors. */
|
||||
const Selectors = {
|
||||
quickGradingSaveRegion: '[data-region="quick-grading-save"]',
|
||||
notifyStudentsCheckbox: 'input[type="checkbox"][name="sendstudentnotifications"]',
|
||||
notifyStudentsHidden: 'input[type="hidden"][name="sendstudentnotifications"]',
|
||||
saveButton: 'button[type="submit"]'
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize module.
|
||||
*/
|
||||
export const init = () => {
|
||||
const quickGradingSaveRegion = document.querySelector(Selectors.quickGradingSaveRegion);
|
||||
if (quickGradingSaveRegion) {
|
||||
const quickGradingSaveButton = quickGradingSaveRegion.querySelector(Selectors.saveButton);
|
||||
// Initialize the submit button.
|
||||
formSubmit.init(quickGradingSaveButton);
|
||||
// Add 'change' event listener to the quick grading save region.
|
||||
quickGradingSaveRegion.addEventListener('change', e => {
|
||||
const notifyStudentsCheckbox = e.target.closest(Selectors.notifyStudentsCheckbox);
|
||||
// The target is the 'Notify student' checkbox.
|
||||
if (notifyStudentsCheckbox) {
|
||||
// The 'Notify student' option uses a hidden input and a checkbox. The hidden input is used to submit '0'
|
||||
// as a workaround when the checkbox is unchecked since unchecked checkboxes are not submitted with the
|
||||
// form. Therefore, we need to enable or disable the hidden input based on the checkbox state.
|
||||
const notifyStudentsHidden = notifyStudentsCheckbox.parentNode.querySelector(Selectors.notifyStudentsHidden);
|
||||
notifyStudentsHidden.disabled = notifyStudentsCheckbox.checked;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -51,18 +51,6 @@ class grading_options_temp_form extends \moodleform {
|
||||
$mform->disable_form_change_checker();
|
||||
|
||||
$mform->addElement('header', 'general', get_string('gradingoptions', 'assign'));
|
||||
// Visible elements.
|
||||
$options = array(10 => '10', 20 => '20', 50 => '50', 100 => '100', -1 => get_string('all'));
|
||||
$maxperpage = get_config('assign', 'maxperpage');
|
||||
if (isset($maxperpage) && $maxperpage != -1) {
|
||||
unset($options[-1]);
|
||||
foreach ($options as $val) {
|
||||
if ($val > $maxperpage) {
|
||||
unset($options[$val]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options);
|
||||
if (!empty($instance['markingallocationopt'])) {
|
||||
$markingfilter = get_string('markerfilter', 'assign');
|
||||
$mform->addElement('select', 'markerfilter', $markingfilter, $instance['markingallocationopt']);
|
||||
|
||||
@@ -1131,23 +1131,6 @@ class renderer extends \plugin_renderer_base {
|
||||
$o .= $this->output->box_start('boxaligncenter gradingtable position-relative');
|
||||
|
||||
$this->page->requires->js_init_call('M.mod_assign.init_grading_table', array());
|
||||
$this->page->requires->string_for_js('nousersselected', 'assign');
|
||||
$this->page->requires->string_for_js('batchoperationconfirmgrantextension', 'assign');
|
||||
$this->page->requires->string_for_js('batchoperationconfirmlock', 'assign');
|
||||
$this->page->requires->string_for_js('batchoperationconfirmremovesubmission', 'assign');
|
||||
$this->page->requires->string_for_js('batchoperationconfirmreverttodraft', 'assign');
|
||||
$this->page->requires->string_for_js('batchoperationconfirmunlock', 'assign');
|
||||
$this->page->requires->string_for_js('batchoperationconfirmaddattempt', 'assign');
|
||||
$this->page->requires->string_for_js('batchoperationconfirmdownloadselected', 'assign');
|
||||
$this->page->requires->string_for_js('batchoperationconfirmsetmarkingworkflowstate', 'assign');
|
||||
$this->page->requires->string_for_js('batchoperationconfirmsetmarkingallocation', 'assign');
|
||||
$this->page->requires->string_for_js('editaction', 'assign');
|
||||
foreach ($table->plugingradingbatchoperations as $plugin => $operations) {
|
||||
foreach ($operations as $operation => $description) {
|
||||
$this->page->requires->string_for_js('batchoperationconfirm' . $operation,
|
||||
'assignfeedback_' . $plugin);
|
||||
}
|
||||
}
|
||||
$o .= $this->flexible_table($table, $table->get_rows_per_page(), true);
|
||||
$o .= $this->output->box_end();
|
||||
|
||||
|
||||
@@ -29,12 +29,12 @@ Feature: In an assignment, teachers can provide feedback comments on student sub
|
||||
And I navigate to "Submissions" in current page administration
|
||||
Then I click on "Quick grading" "checkbox"
|
||||
And I set the field "Feedback comments" to "Feedback from teacher."
|
||||
And I press "Save all quick grading changes"
|
||||
And I click on "Save" "button" in the "sticky-footer" "region"
|
||||
And I should see "The grade changes were saved"
|
||||
And I press "Continue"
|
||||
And I should see "Feedback from teacher."
|
||||
And I set the field "Feedback comments" to ""
|
||||
And I press "Save all quick grading changes"
|
||||
And I click on "Save" "button" in the "sticky-footer" "region"
|
||||
And I should see "The grade changes were saved"
|
||||
And I press "Continue"
|
||||
And I should not see "Feedback from teacher."
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
$string['batchoperationconfirmuploadfiles'] = 'Upload one or more feedback files for all selected users?';
|
||||
$string['batchoperationuploadfiles'] = 'Upload feedback';
|
||||
$string['batchuploadfiles'] = 'Upload feedback files for multiple users';
|
||||
$string['batchuploadfilesforusers'] = 'Send feedback files to {$a} selected user(s).';
|
||||
$string['configmaxbytes'] = 'Maximum file size';
|
||||
|
||||
@@ -433,14 +433,18 @@ class assign_feedback_file extends assign_feedback_plugin {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the batch grading operations performed by this plugin.
|
||||
* This plugin supports batch upload files and upload zip.
|
||||
*
|
||||
* @return array The list of batch grading operations
|
||||
*/
|
||||
public function get_grading_batch_operations() {
|
||||
return array('uploadfiles'=>get_string('uploadfiles', 'assignfeedback_file'));
|
||||
public function get_grading_batch_operation_details() {
|
||||
global $OUTPUT;
|
||||
|
||||
return [
|
||||
(object) [
|
||||
'key' => 'uploadfiles',
|
||||
'label' => get_string('batchoperationuploadfiles', 'assignfeedback_file'),
|
||||
'icon' => $OUTPUT->pix_icon('i/upload', ''),
|
||||
'confirmationtitle' => get_string('uploadfiles', 'assignfeedback_file'),
|
||||
'confirmationquestion' => get_string('batchoperationconfirmuploadfiles', 'assignfeedback_file'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -158,14 +158,33 @@ abstract class assign_feedback_plugin extends assign_plugin {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of detailed batch grading operations supported by this plugin.
|
||||
*
|
||||
* @return array - An array of objects containing batch operation details. Each object should contain:
|
||||
* - 'key': the action identifier (string)
|
||||
* - 'label': the button label (string)
|
||||
* - 'icon': the button icon (string)
|
||||
* - 'confirmationtitle': the title for the confirmation modal (string)
|
||||
* - 'confirmationquestion': the question for the confirmation modal (string)
|
||||
*/
|
||||
public function get_grading_batch_operation_details() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the batch grading operations supported by this plugin.
|
||||
*
|
||||
* @return array - An array of action and description strings.
|
||||
* The action will be passed to grading_batch_operation.
|
||||
* @deprecated since 4.5, use get_grading_batch_operation_details() instead.
|
||||
* @todo Final deprecation in Moodle 6.0. See MDL-82856.
|
||||
*/
|
||||
#[\core\attribute\deprecated('get_grading_batch_operation_details', since: '4.5', mdl: 'MDL-80750')]
|
||||
public function get_grading_batch_operations() {
|
||||
return array();
|
||||
\core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]);
|
||||
|
||||
return array_column(static::get_grading_batch_operation_details(), 'confirmationtitle', 'key');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,12 +33,30 @@ require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
* @package mod_assign
|
||||
* @copyright 2012 NetSpot {@link http://www.netspot.com.au}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since 4.5
|
||||
* @todo Final deprecation in Moodle 6.0. See MDL-82869.
|
||||
*/
|
||||
#[\core\attribute\deprecated(
|
||||
replacement: null,
|
||||
since: '4.5',
|
||||
reason: 'It is no longer used.',
|
||||
mdl: 'MDL-80750',
|
||||
)]
|
||||
class mod_assign_grading_batch_operations_form extends moodleform {
|
||||
/**
|
||||
* Define this form - called by the parent constructor.
|
||||
*
|
||||
* @deprecated since 4.5
|
||||
*/
|
||||
#[\core\attribute\deprecated(
|
||||
replacement: null,
|
||||
since: '4.5',
|
||||
reason: 'It is no longer used.',
|
||||
mdl: 'MDL-80750'
|
||||
)]
|
||||
public function definition() {
|
||||
\core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]);
|
||||
|
||||
global $CFG;
|
||||
$mform = $this->_form;
|
||||
$instance = $this->_customdata;
|
||||
@@ -100,4 +118,3 @@ class mod_assign_grading_batch_operations_form extends moodleform {
|
||||
$mform->addElement('group', 'actionsgrp', $batchdescription, $objs, ' ', false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+120
-12
@@ -40,6 +40,8 @@ class assign_grading_table extends table_sql implements renderable {
|
||||
private $assignment = null;
|
||||
/** @var int $perpage */
|
||||
private $perpage = 10;
|
||||
/** @var int[] $pagingoptions Available pagination options */
|
||||
private $pagingoptions = [10, 20, 50, 100];
|
||||
/** @var int $rownum (global index of current row in table) */
|
||||
private $rownum = -1;
|
||||
/** @var renderer_base for getting output */
|
||||
@@ -58,8 +60,6 @@ class assign_grading_table extends table_sql implements renderable {
|
||||
private $groupsubmissions = array();
|
||||
/** @var array $submissiongroups - A static cache of submission groups */
|
||||
private $submissiongroups = array();
|
||||
/** @var string $plugingradingbatchoperations - List of plugin supported batch operations */
|
||||
public $plugingradingbatchoperations = array();
|
||||
/** @var array $plugincache - A cache of plugin lookups to match a column name to a plugin efficiently */
|
||||
private $plugincache = array();
|
||||
/** @var array $scale - A list of the keys and descriptions for the custom scale */
|
||||
@@ -100,16 +100,6 @@ class assign_grading_table extends table_sql implements renderable {
|
||||
$this->hasviewblind = has_capability('mod/assign:viewblinddetails',
|
||||
$this->assignment->get_context());
|
||||
|
||||
foreach ($assignment->get_feedback_plugins() as $plugin) {
|
||||
if ($plugin->is_visible() && $plugin->is_enabled()) {
|
||||
foreach ($plugin->get_grading_batch_operations() as $action => $description) {
|
||||
if (empty($this->plugingradingbatchoperations)) {
|
||||
$this->plugingradingbatchoperations[$plugin->get_type()] = array();
|
||||
}
|
||||
$this->plugingradingbatchoperations[$plugin->get_type()][$action] = $description;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->perpage = $perpage;
|
||||
$this->quickgrading = $quickgrading && $this->hasgrade;
|
||||
$this->output = $PAGE->get_renderer('mod_assign');
|
||||
@@ -929,6 +919,7 @@ class assign_grading_table extends table_sql implements renderable {
|
||||
$selectcol .= get_string('selectuser', 'assign', $this->assignment->fullname($row));
|
||||
$selectcol .= '</label>';
|
||||
$selectcol .= '<input type="checkbox"
|
||||
class="ignoredirty"
|
||||
id="selectuser_' . $row->userid . '"
|
||||
name="selectedusers"
|
||||
value="' . $row->userid . '"/>';
|
||||
@@ -1824,4 +1815,121 @@ class assign_grading_table extends table_sql implements renderable {
|
||||
}
|
||||
parent::setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for the paging bar.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_paging_bar(): string {
|
||||
global $OUTPUT;
|
||||
|
||||
if ($this->use_pages) {
|
||||
$pagingbar = new paging_bar($this->totalrows, $this->currpage, $this->pagesize, $this->baseurl);
|
||||
$pagingbar->pagevar = $this->request[TABLE_VAR_PAGE];
|
||||
return $OUTPUT->render($pagingbar);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for the paging selector.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_paging_selector(): string {
|
||||
global $OUTPUT;
|
||||
|
||||
if ($this->use_pages) {
|
||||
$pagingoptions = [...$this->pagingoptions, $this->perpage]; // To make sure the actual page size is within the options.
|
||||
$pagingoptions = array_unique($pagingoptions);
|
||||
sort($pagingoptions);
|
||||
$pagingoptions = array_combine($pagingoptions, $pagingoptions);
|
||||
$maxperpage = get_config('assign', 'maxperpage');
|
||||
if (isset($maxperpage) && $maxperpage != -1) {
|
||||
// Remove any options that are greater than the maxperpage.
|
||||
$pagingoptions = array_filter($pagingoptions, fn($value) => $value <= $maxperpage);
|
||||
} else {
|
||||
$pagingoptions[-1] = get_string('all');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'baseurl' => $this->baseurl->out(false),
|
||||
'options' => array_map(fn($key, $name): array => [
|
||||
'name' => $name,
|
||||
'value' => $key,
|
||||
'selected' => $key == $this->perpage,
|
||||
], array_keys($pagingoptions), $pagingoptions),
|
||||
];
|
||||
|
||||
return $OUTPUT->render_from_template('mod_assign/grading_paging_selector', $data);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the HTML output.
|
||||
* This function is essentially a copy of the parent function except the paging bar not being rendered.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function finish_html(): void {
|
||||
if (!$this->started_output) {
|
||||
// No data has been added to the table.
|
||||
$this->print_nothing_to_display();
|
||||
} else {
|
||||
// Print empty rows to fill the table to the current pagesize.
|
||||
// This is done so the header aria-controls attributes do not point to
|
||||
// non-existent elements.
|
||||
$emptyrow = array_fill(0, count($this->columns), '');
|
||||
while ($this->currentrow < $this->pagesize) {
|
||||
$this->print_row($emptyrow, 'emptyrow');
|
||||
}
|
||||
|
||||
echo html_writer::end_tag('tbody');
|
||||
echo html_writer::end_tag('table');
|
||||
if ($this->responsive) {
|
||||
echo html_writer::end_tag('div');
|
||||
}
|
||||
$this->wrap_html_finish();
|
||||
|
||||
if (in_array(TABLE_P_BOTTOM, $this->showdownloadbuttonsat)) {
|
||||
echo $this->download_buttons();
|
||||
}
|
||||
|
||||
// Render the dynamic table footer.
|
||||
echo $this->get_dynamic_table_html_end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the HTML output.
|
||||
* This function is essentially a copy of the parent function except the paging bar not being rendered.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function start_html(): void {
|
||||
// Render the dynamic table header.
|
||||
echo $this->get_dynamic_table_html_start();
|
||||
|
||||
// Render button to allow user to reset table preferences.
|
||||
echo $this->render_reset_button();
|
||||
|
||||
// Do we need to print initial bars?
|
||||
$this->print_initials_bar();
|
||||
|
||||
if (in_array(TABLE_P_TOP, $this->showdownloadbuttonsat)) {
|
||||
echo $this->download_buttons();
|
||||
}
|
||||
|
||||
$this->wrap_html_start();
|
||||
// Start of main data table.
|
||||
|
||||
if ($this->responsive) {
|
||||
echo html_writer::start_tag('div', ['class' => 'no-overflow']);
|
||||
}
|
||||
echo html_writer::start_tag('table', $this->attributes) . $this->render_caption();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,7 @@ $string['attemptreopenmethod_untilpass_help'] = 'After each attempt, the next wi
|
||||
$string['availability'] = 'Availability';
|
||||
$string['back'] = 'Back';
|
||||
$string['backtoassignment'] = 'Back to assignment';
|
||||
$string['batchoperationaddattempt'] = 'Grant attempt';
|
||||
$string['batchoperationsdescription'] = 'With selected...';
|
||||
$string['batchoperationconfirmlock'] = 'Lock all selected submissions?';
|
||||
$string['batchoperationconfirmgrantextension'] = 'Grant an extension to all selected submissions?';
|
||||
@@ -132,9 +133,14 @@ $string['batchoperationconfirmaddattempt'] = 'Allow another attempt for selected
|
||||
$string['batchoperationconfirmsetmarkingworkflowstate'] = 'Set marking workflow state for all selected submissions?';
|
||||
$string['batchoperationconfirmsetmarkingallocation'] = 'Set marking allocation for all selected submissions?';
|
||||
$string['batchoperationconfirmdownloadselected'] = 'Download selected submissions?';
|
||||
$string['batchoperationlock'] = 'lock submissions';
|
||||
$string['batchoperationunlock'] = 'unlock submissions';
|
||||
$string['batchoperationreverttodraft'] = 'revert submissions to draft';
|
||||
$string['batchoperationdownloadselected'] = 'Download';
|
||||
$string['batchoperationgrantextension'] = 'Extend';
|
||||
$string['batchoperationlock'] = 'Lock';
|
||||
$string['batchoperationremovesubmission'] = 'Delete';
|
||||
$string['batchoperationunlock'] = 'Unlock';
|
||||
$string['batchoperationreverttodraft'] = 'Revert to draft';
|
||||
$string['batchoperationsetmarkingallocation'] = 'Allocate marker';
|
||||
$string['batchoperationsetmarkingworkflowstate'] = 'Change marking state';
|
||||
$string['batchsetallocatedmarker'] = 'Set allocated marker for {$a} selected user(s).';
|
||||
$string['batchsetmarkingworkflowstateforusers'] = 'Set marking workflow state for {$a} selected user(s).';
|
||||
$string['beginassignment'] = 'Begin assignment';
|
||||
@@ -209,7 +215,6 @@ $string['editsubmission'] = 'Edit submission';
|
||||
$string['editsubmissionother'] = 'Edit submission for {$a}';
|
||||
$string['editsubmission_help'] = 'You can still make changes to your submission.';
|
||||
$string['editingstatus'] = 'Editing status';
|
||||
$string['editaction'] = 'Actions...';
|
||||
$string['enabled'] = 'Enabled';
|
||||
$string['enabletimelimit'] = 'Enable timed assignments';
|
||||
$string['enabletimelimit_help'] = 'If enabled, you can set a time limit on assignment settings page.';
|
||||
@@ -434,6 +439,7 @@ $string['noteamgrader'] = 'Not a member of any group, so unable to make submissi
|
||||
$string['notgraded'] = 'Not graded';
|
||||
$string['notgradedyet'] = 'Not graded yet';
|
||||
$string['notifications'] = 'Notifications';
|
||||
$string['notifystudents'] = 'Notify students';
|
||||
$string['nousersselected'] = 'No users selected';
|
||||
$string['nousers'] = 'No users';
|
||||
$string['numberofdraftsubmissions'] = 'Drafts';
|
||||
@@ -525,7 +531,6 @@ $string['reverttodraft'] = 'Revert the submission to draft status';
|
||||
$string['reverttodraftshort'] = 'Revert the submission to draft';
|
||||
$string['reviewed'] = 'Reviewed';
|
||||
$string['save'] = 'Save';
|
||||
$string['saveallquickgradingchanges'] = 'Save all quick grading changes';
|
||||
$string['saveandcontinue'] = 'Save and continue';
|
||||
$string['savechanges'] = 'Save changes';
|
||||
$string['savegradingresult'] = 'Grade';
|
||||
@@ -702,7 +707,9 @@ $string['xofy'] = '{$a->x} of {$a->y}';
|
||||
$string['attemptreopenmethod_none'] = 'Never';
|
||||
$string['choosegradingaction'] = 'Grading action';
|
||||
$string['downloadasfolders_help'] = 'Assignment submissions may be downloaded in folders. Each submission is then put in a separate folder, with the folder structure kept for any subfolders, and files are not renamed.';
|
||||
$string['editaction'] = 'Actions...';
|
||||
$string['groupoverridesdeleted'] = 'Group overrides deleted';
|
||||
$string['saveallquickgradingchanges'] = 'Save all quick grading changes';
|
||||
$string['updategrade'] = 'Update grade';
|
||||
$string['useroverridesdeleted'] = 'User overrides deleted';
|
||||
$string['viewgrader'] = 'View Grader';
|
||||
|
||||
@@ -5,3 +5,5 @@ choosegradingaction,mod_assign
|
||||
updategrade,mod_assign
|
||||
viewgrader,mod_assign
|
||||
downloadasfolders_help,mod_assign
|
||||
editaction,mod_assign
|
||||
saveallquickgradingchanges,mod_assign
|
||||
|
||||
+130
-134
@@ -594,7 +594,7 @@ class assign {
|
||||
$action = 'viewsubmitforgradingerror';
|
||||
}
|
||||
} else if ($action == 'gradingbatchoperation') {
|
||||
$action = $this->process_grading_batch_operation($mform);
|
||||
$action = $this->process_grading_batch_operation();
|
||||
if ($action == 'grading') {
|
||||
$action = 'redirect';
|
||||
$nextpageparams['action'] = 'grading';
|
||||
@@ -699,20 +699,20 @@ class assign {
|
||||
} else if ($action == 'grantextension') {
|
||||
$o .= $this->view_grant_extension($mform);
|
||||
} else if ($action == 'revealidentities') {
|
||||
$o .= $this->view_reveal_identities_confirm($mform);
|
||||
$o .= $this->view_reveal_identities_confirm();
|
||||
} else if ($action == 'removesubmissionconfirm') {
|
||||
$PAGE->add_body_class('limitedwidth');
|
||||
$o .= $this->view_remove_submission_confirm();
|
||||
} else if ($action == 'plugingradingbatchoperation') {
|
||||
$o .= $this->view_plugin_grading_batch_operation($mform);
|
||||
$o .= $this->view_plugin_grading_batch_operation();
|
||||
} else if ($action == 'viewpluginpage') {
|
||||
$o .= $this->view_plugin_page();
|
||||
} else if ($action == 'viewcourseindex') {
|
||||
$o .= $this->view_course_index();
|
||||
} else if ($action == 'viewbatchsetmarkingworkflowstate') {
|
||||
$o .= $this->view_batch_set_workflow_state($mform);
|
||||
$o .= $this->view_batch_set_workflow_state();
|
||||
} else if ($action == 'viewbatchmarkingallocation') {
|
||||
$o .= $this->view_batch_markingallocation($mform);
|
||||
$o .= $this->view_batch_markingallocation();
|
||||
} else if ($action == 'viewsubmitforgradingerror') {
|
||||
$o .= $this->view_error_page(get_string('submitforgrading', 'assign'), $notices);
|
||||
} else if ($action == 'fixrescalednullgrades') {
|
||||
@@ -4478,12 +4478,11 @@ class assign {
|
||||
* @return string
|
||||
*/
|
||||
protected function view_grading_table() {
|
||||
global $USER, $CFG, $SESSION, $PAGE;
|
||||
global $USER, $CFG, $SESSION, $PAGE, $OUTPUT;
|
||||
|
||||
// Include grading options form.
|
||||
require_once($CFG->dirroot . '/mod/assign/gradingoptionsform.php');
|
||||
require_once($CFG->dirroot . '/mod/assign/quickgradingform.php');
|
||||
require_once($CFG->dirroot . '/mod/assign/gradingbatchoperationsform.php');
|
||||
|
||||
$submittedfilter = optional_param('status', null, PARAM_ALPHA);
|
||||
if (isset($submittedfilter)) {
|
||||
@@ -4504,6 +4503,11 @@ class assign {
|
||||
set_user_preference('assign_downloadasfolders', $submitteddownloadasfolders);
|
||||
}
|
||||
|
||||
$submittedperpage = optional_param('perpage', null, PARAM_INT);
|
||||
if (isset($submittedperpage)) {
|
||||
set_user_preference('assign_perpage', $submittedperpage);
|
||||
}
|
||||
|
||||
$o = '';
|
||||
$cmid = $this->get_course_module()->id;
|
||||
|
||||
@@ -4565,28 +4569,7 @@ class assign {
|
||||
'',
|
||||
$classoptions);
|
||||
|
||||
$batchformparams = array('cm'=>$cmid,
|
||||
'submissiondrafts'=>$this->get_instance()->submissiondrafts,
|
||||
'duedate'=>$this->get_instance()->duedate,
|
||||
'maxattempts' => $this->get_instance()->maxattempts,
|
||||
'attemptreopenmethod'=>$this->get_instance()->attemptreopenmethod,
|
||||
'feedbackplugins'=>$this->get_feedback_plugins(),
|
||||
'context'=>$this->get_context(),
|
||||
'markingworkflow'=>$markingworkflow,
|
||||
'markingallocation'=>$markingallocation);
|
||||
$classoptions = [
|
||||
'class' => 'gradingbatchoperationsform',
|
||||
'data-double-submit-protection' => 'off',
|
||||
];
|
||||
|
||||
$gradingbatchoperationsform = new mod_assign_grading_batch_operations_form(null,
|
||||
$batchformparams,
|
||||
'post',
|
||||
'',
|
||||
$classoptions);
|
||||
|
||||
$gradingoptionsdata = new stdClass();
|
||||
$gradingoptionsdata->perpage = $perpage;
|
||||
$gradingoptionsdata->markerfilter = $markerfilter;
|
||||
$gradingoptionsform->set_data($gradingoptionsdata);
|
||||
|
||||
@@ -4619,42 +4602,86 @@ class assign {
|
||||
}
|
||||
|
||||
// Load and print the table of submissions.
|
||||
if ($showquickgrading && $quickgrading) {
|
||||
$gradingtable = new assign_grading_table($this, $perpage, $filter, 0, true);
|
||||
$gradingtable->responsive = false;
|
||||
$table = $this->get_renderer()->render($gradingtable);
|
||||
$usequickgrading = $showquickgrading && $quickgrading;
|
||||
$gradingtable = new assign_grading_table($this, $perpage, $filter, 0, $usequickgrading);
|
||||
$gradingtable->responsive = false;
|
||||
$table = $this->get_renderer()->render($gradingtable);
|
||||
$footerdata = [
|
||||
'perpage' => $gradingtable->get_paging_selector(),
|
||||
'pagingbar' => $gradingtable->get_paging_bar(),
|
||||
'hassubmit' => $usequickgrading,
|
||||
'sendstudentnotifications' => $this->get_instance()->sendstudentnotifications,
|
||||
];
|
||||
$footer = new core\output\sticky_footer($OUTPUT->render_from_template('mod_assign/grading_sticky_footer', $footerdata));
|
||||
|
||||
if ($usequickgrading) {
|
||||
$page = optional_param('page', null, PARAM_INT);
|
||||
$quickformparams = array('cm'=>$this->get_course_module()->id,
|
||||
'gradingtable'=>$table,
|
||||
'sendstudentnotifications' => $this->get_instance()->sendstudentnotifications,
|
||||
'page' => $page);
|
||||
$PAGE->requires->js_call_amd('mod_assign/quick_grading', 'init', []);
|
||||
$quickformparams = [
|
||||
'cm' => $this->get_course_module()->id,
|
||||
'gradingtable' => $table,
|
||||
'page' => $page,
|
||||
'footer' => $this->get_renderer()->render($footer),
|
||||
];
|
||||
$quickgradingform = new mod_assign_quick_grading_form(null, $quickformparams);
|
||||
|
||||
$o .= $this->get_renderer()->render(new assign_form('quickgradingform', $quickgradingform));
|
||||
} else {
|
||||
$gradingtable = new assign_grading_table($this, $perpage, $filter, 0, false);
|
||||
$gradingtable->responsive = false;
|
||||
$o .= $this->get_renderer()->render($gradingtable);
|
||||
$o .= $table;
|
||||
$o .= $this->get_renderer()->render($footer);
|
||||
}
|
||||
|
||||
if ($this->can_grade()) {
|
||||
// We need to store the order of uses in the table as the person may wish to grade them.
|
||||
// This is done based on the row number of the user.
|
||||
// Pagination has be added before this because calling get_column_data will reset the pagination.
|
||||
$useridlist = $gradingtable->get_column_data('userid');
|
||||
$SESSION->mod_assign_useridlist[$this->get_useridlist_key()] = $useridlist;
|
||||
}
|
||||
|
||||
$currentgroup = groups_get_activity_group($this->get_course_module(), true);
|
||||
$users = array_keys($this->list_participants($currentgroup, true));
|
||||
if (count($users) != 0 && $this->can_grade()) {
|
||||
// If no enrolled user in a course then don't display the batch operations feature.
|
||||
$assignform = new assign_form('gradingbatchoperationsform', $gradingbatchoperationsform);
|
||||
$o .= $this->get_renderer()->render($assignform);
|
||||
}
|
||||
$assignform = new assign_form('gradingoptionsform',
|
||||
$gradingoptionsform,
|
||||
'M.mod_assign.init_grading_options');
|
||||
$o .= $this->get_renderer()->render($assignform);
|
||||
|
||||
$currentgroup = groups_get_activity_group($this->get_course_module(), true);
|
||||
$users = array_keys($this->list_participants($currentgroup, true));
|
||||
if (count($users) != 0 && $this->can_grade()) {
|
||||
$jsparams = [];
|
||||
$jsparams['message'] = !empty($CFG->messaging)
|
||||
&& has_all_capabilities(['moodle/site:sendmessage', 'moodle/course:bulkmessaging'], $this->context);
|
||||
$jsparams['submissiondrafts'] = !empty($this->get_instance()->submissiondrafts);
|
||||
$jsparams['removesubmission'] = has_capability('mod/assign:editothersubmission', $this->context);
|
||||
$jsparams['extend'] = $this->get_instance()->duedate && has_capability('mod/assign:grantextension', $this->context);
|
||||
|
||||
$multipleattemptsallowed = $this->get_instance()->maxattempts > 1
|
||||
|| $this->get_instance()->maxattempts == ASSIGN_UNLIMITED_ATTEMPTS;
|
||||
$jsparams['grantattempt'] =
|
||||
$multipleattemptsallowed && $this->get_instance()->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL;
|
||||
|
||||
$jsparams['pluginoperations'] = [];
|
||||
foreach ($this->get_feedback_plugins() as $plugin) {
|
||||
if ($plugin->is_visible() && $plugin->is_enabled()) {
|
||||
foreach ($plugin->get_grading_batch_operation_details() as $operation) {
|
||||
$jsparams['pluginoperations'][] = [
|
||||
'key' => 'plugingradingbatchoperation_' . $plugin->get_type() . '_' . $operation->key,
|
||||
'label' => $operation->label,
|
||||
'icon' => $operation->icon,
|
||||
'confirmationtitle' => $operation->confirmationtitle,
|
||||
'confirmationquestion' => $operation->confirmationquestion,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$jsparams['workflowstate'] = !empty($this->get_instance()->markingworkflow);
|
||||
$jsparams['markingallocation'] = !empty($this->get_instance()->markingallocation);
|
||||
$jsparams['cmid'] = $this->get_course_module()->id;
|
||||
$jsparams['sesskey'] = sesskey();
|
||||
|
||||
$PAGE->requires->js_call_amd('mod_assign/bulkactions/grading/bulk_actions', 'init', [$jsparams]);
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
@@ -5006,112 +5033,84 @@ class assign {
|
||||
|
||||
/**
|
||||
* Allows the plugin to show a batch grading operation page.
|
||||
* You should confirm sesskey before calling this function.
|
||||
*
|
||||
* @param moodleform $mform
|
||||
* @return none
|
||||
*/
|
||||
protected function view_plugin_grading_batch_operation($mform) {
|
||||
protected function view_plugin_grading_batch_operation() {
|
||||
require_capability('mod/assign:grade', $this->context);
|
||||
$prefix = 'plugingradingbatchoperation_';
|
||||
|
||||
if ($data = $mform->get_data()) {
|
||||
$tail = substr($data->operation, strlen($prefix));
|
||||
list($plugintype, $action) = explode('_', $tail, 2);
|
||||
$operation = required_param('operation', PARAM_ALPHAEXT);
|
||||
|
||||
$plugin = $this->get_feedback_plugin_by_type($plugintype);
|
||||
if ($plugin) {
|
||||
$users = $data->selectedusers;
|
||||
$userlist = explode(',', $users);
|
||||
echo $plugin->grading_batch_operation($action, $userlist);
|
||||
return;
|
||||
}
|
||||
$tail = substr($operation, strlen($prefix));
|
||||
list($plugintype, $action) = explode('_', $tail, 2);
|
||||
|
||||
$plugin = $this->get_feedback_plugin_by_type($plugintype);
|
||||
if ($plugin) {
|
||||
$users = required_param('selectedusers', PARAM_SEQUENCE);
|
||||
$userlist = explode(',', $users);
|
||||
echo $plugin->grading_batch_operation($action, $userlist);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \moodle_exception('invalidformdata', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the user to confirm they want to perform this batch operation
|
||||
*
|
||||
* @param moodleform $mform Set to a grading batch operations form
|
||||
* @return string - the page to view after processing these actions
|
||||
*/
|
||||
protected function process_grading_batch_operation(& $mform) {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/gradingbatchoperationsform.php');
|
||||
protected function process_grading_batch_operation() {
|
||||
require_sesskey();
|
||||
|
||||
$markingallocation = $this->get_instance()->markingworkflow &&
|
||||
$this->get_instance()->markingallocation &&
|
||||
has_capability('mod/assign:manageallocations', $this->context);
|
||||
$operation = required_param('operation', PARAM_ALPHAEXT);
|
||||
$selectedusers = required_param('selectedusers', PARAM_SEQUENCE);
|
||||
|
||||
$batchformparams = array('cm'=>$this->get_course_module()->id,
|
||||
'submissiondrafts'=>$this->get_instance()->submissiondrafts,
|
||||
'duedate'=>$this->get_instance()->duedate,
|
||||
'maxattempts' => $this->get_instance()->maxattempts,
|
||||
'attemptreopenmethod'=>$this->get_instance()->attemptreopenmethod,
|
||||
'feedbackplugins'=>$this->get_feedback_plugins(),
|
||||
'context'=>$this->get_context(),
|
||||
'markingworkflow'=>$this->get_instance()->markingworkflow,
|
||||
'markingallocation'=>$markingallocation);
|
||||
$formclasses = [
|
||||
'class' => 'gradingbatchoperationsform',
|
||||
'data-double-submit-protection' => 'off'
|
||||
];
|
||||
// Get the list of users.
|
||||
$userlist = explode(',', $selectedusers);
|
||||
|
||||
$mform = new mod_assign_grading_batch_operations_form(null,
|
||||
$batchformparams,
|
||||
'post',
|
||||
'',
|
||||
$formclasses);
|
||||
$prefix = 'plugingradingbatchoperation_';
|
||||
|
||||
if ($data = $mform->get_data()) {
|
||||
// Get the list of users.
|
||||
$users = $data->selectedusers;
|
||||
$userlist = explode(',', $users);
|
||||
if ($operation == 'grantextension') {
|
||||
return 'grantextension';
|
||||
} else if ($operation == 'setmarkingworkflowstate') {
|
||||
return 'viewbatchsetmarkingworkflowstate';
|
||||
} else if ($operation == 'setmarkingallocation') {
|
||||
return 'viewbatchmarkingallocation';
|
||||
} else if (strpos($operation, $prefix) === 0) {
|
||||
$tail = substr($operation, strlen($prefix));
|
||||
list($plugintype, $action) = explode('_', $tail, 2);
|
||||
|
||||
$prefix = 'plugingradingbatchoperation_';
|
||||
|
||||
if ($data->operation == 'grantextension') {
|
||||
// Reset the form so the grant extension page will create the extension form.
|
||||
$mform = null;
|
||||
return 'grantextension';
|
||||
} else if ($data->operation == 'setmarkingworkflowstate') {
|
||||
return 'viewbatchsetmarkingworkflowstate';
|
||||
} else if ($data->operation == 'setmarkingallocation') {
|
||||
return 'viewbatchmarkingallocation';
|
||||
} else if (strpos($data->operation, $prefix) === 0) {
|
||||
$tail = substr($data->operation, strlen($prefix));
|
||||
list($plugintype, $action) = explode('_', $tail, 2);
|
||||
|
||||
$plugin = $this->get_feedback_plugin_by_type($plugintype);
|
||||
if ($plugin) {
|
||||
return 'plugingradingbatchoperation';
|
||||
}
|
||||
$plugin = $this->get_feedback_plugin_by_type($plugintype);
|
||||
if ($plugin) {
|
||||
return 'plugingradingbatchoperation';
|
||||
}
|
||||
}
|
||||
|
||||
if ($data->operation == 'downloadselected') {
|
||||
$this->download_submissions($userlist);
|
||||
} else {
|
||||
foreach ($userlist as $userid) {
|
||||
if ($data->operation == 'lock') {
|
||||
$this->process_lock_submission($userid);
|
||||
} else if ($data->operation == 'unlock') {
|
||||
$this->process_unlock_submission($userid);
|
||||
} else if ($data->operation == 'reverttodraft') {
|
||||
$this->process_revert_to_draft($userid);
|
||||
} else if ($data->operation == 'removesubmission') {
|
||||
$this->process_remove_submission($userid);
|
||||
} else if ($data->operation == 'addattempt') {
|
||||
if (!$this->get_instance()->teamsubmission) {
|
||||
$this->process_add_attempt($userid);
|
||||
}
|
||||
if ($operation == 'downloadselected') {
|
||||
$this->download_submissions($userlist);
|
||||
} else {
|
||||
foreach ($userlist as $userid) {
|
||||
if ($operation == 'lock') {
|
||||
$this->process_lock_submission($userid);
|
||||
} else if ($operation == 'unlock') {
|
||||
$this->process_unlock_submission($userid);
|
||||
} else if ($operation == 'reverttodraft') {
|
||||
$this->process_revert_to_draft($userid);
|
||||
} else if ($operation == 'removesubmission') {
|
||||
$this->process_remove_submission($userid);
|
||||
} else if ($operation == 'addattempt') {
|
||||
if (!$this->get_instance()->teamsubmission) {
|
||||
$this->process_add_attempt($userid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->get_instance()->teamsubmission && $data->operation == 'addattempt') {
|
||||
// This needs to be handled separately so that each team submission is only re-opened one time.
|
||||
$this->process_add_attempt_group($userlist);
|
||||
}
|
||||
}
|
||||
if ($this->get_instance()->teamsubmission && $operation == 'addattempt') {
|
||||
// This needs to be handled separately so that each team submission is only re-opened one time.
|
||||
$this->process_add_attempt_group($userlist);
|
||||
}
|
||||
|
||||
return 'grading';
|
||||
@@ -5119,19 +5118,18 @@ class assign {
|
||||
|
||||
/**
|
||||
* Shows a form that allows the workflow state for selected submissions to be changed.
|
||||
* You should confirm sesskey before calling this function.
|
||||
*
|
||||
* @param moodleform $mform Set to a grading batch operations form
|
||||
* @return string - the page to view after processing these actions
|
||||
*/
|
||||
protected function view_batch_set_workflow_state($mform) {
|
||||
protected function view_batch_set_workflow_state() {
|
||||
global $CFG, $DB;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/batchsetmarkingworkflowstateform.php');
|
||||
|
||||
$o = '';
|
||||
|
||||
$submitteddata = $mform->get_data();
|
||||
$users = $submitteddata->selectedusers;
|
||||
$users = required_param('selectedusers', PARAM_SEQUENCE);
|
||||
$userlist = explode(',', $users);
|
||||
|
||||
$formdata = array('id' => $this->get_course_module()->id,
|
||||
@@ -5184,19 +5182,18 @@ class assign {
|
||||
|
||||
/**
|
||||
* Shows a form that allows the allocated marker for selected submissions to be changed.
|
||||
* You should confirm sesskey before calling this function.
|
||||
*
|
||||
* @param moodleform $mform Set to a grading batch operations form
|
||||
* @return string - the page to view after processing these actions
|
||||
*/
|
||||
public function view_batch_markingallocation($mform) {
|
||||
public function view_batch_markingallocation() {
|
||||
global $CFG, $DB;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/batchsetallocatedmarkerform.php');
|
||||
|
||||
$o = '';
|
||||
|
||||
$submitteddata = $mform->get_data();
|
||||
$users = $submitteddata->selectedusers;
|
||||
$users = required_param('selectedusers', PARAM_SEQUENCE);
|
||||
$userlist = explode(',', $users);
|
||||
|
||||
$formdata = array('id' => $this->get_course_module()->id,
|
||||
@@ -7426,7 +7423,6 @@ class assign {
|
||||
];
|
||||
$mform = new mod_assign\form\grading_options_temp_form(null, $gradingoptionsparams);
|
||||
if ($formdata = $mform->get_data()) {
|
||||
set_user_preference('assign_perpage', $formdata->perpage);
|
||||
if (isset($formdata->markerfilter)) {
|
||||
set_user_preference('assign_markerfilter', $formdata->markerfilter);
|
||||
}
|
||||
|
||||
@@ -69,53 +69,6 @@ M.mod_assign.init_grading_table = function(Y) {
|
||||
});
|
||||
}
|
||||
|
||||
const batchform = Y.one('form.gradingbatchoperationsform');
|
||||
if (batchform) {
|
||||
batchform.on('submit', function(e) {
|
||||
M.util.js_pending('mod_assign/module.js:batch:submit');
|
||||
let selectedusers = [];
|
||||
checkboxes.each(function(node) {
|
||||
if (node.get('checked')) {
|
||||
selectedusers.push(node.get('value'));
|
||||
}
|
||||
});
|
||||
|
||||
const operation = Y.one('#id_operation');
|
||||
const usersinput = Y.one('input.selectedusers');
|
||||
usersinput.set('value', selectedusers.join(','));
|
||||
if (selectedusers.length === 0) {
|
||||
alert(M.util.get_string('nousersselected', 'assign'));
|
||||
e.preventDefault();
|
||||
} else {
|
||||
let action = operation.get('value');
|
||||
const prefix = 'plugingradingbatchoperation_';
|
||||
let confirmmessage = false;
|
||||
if (action.indexOf(prefix) === 0) {
|
||||
const pluginaction = action.slice(prefix.length);
|
||||
const plugin = pluginaction.split('_')[0];
|
||||
action = pluginaction.slice(plugin.length + 1);
|
||||
confirmmessage = M.util.get_string('batchoperationconfirm' + action, 'assignfeedback_' + plugin);
|
||||
} else if (action === 'message') {
|
||||
e.preventDefault();
|
||||
require(['core_message/message_send_bulk'], function(BulkSender) {
|
||||
BulkSender.showModal(selectedusers, function() {
|
||||
document.getElementById('page-header').scrollIntoView();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
confirmmessage = M.util.get_string('batchoperationconfirm' + operation.get('value'), 'assign');
|
||||
}
|
||||
// Complete here the action (js_complete event) when we send a bulk message, or we have a confirmation message.
|
||||
// When the confirmation dialogue is completed, the event is fired.
|
||||
if (action === 'message' || confirmmessage !== false && !confirm(confirmmessage)) {
|
||||
M.util.js_complete('mod_assign/module.js:batch:submit');
|
||||
e.preventDefault();
|
||||
}
|
||||
// Note: Do not js_complete. The page being reloaded will empty it.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var quickgrade = Y.all('.gradingtable .quickgrade');
|
||||
quickgrade.each(function(quick) {
|
||||
quick.on('change', function(e) {
|
||||
@@ -127,10 +80,6 @@ M.mod_assign.init_grading_table = function(Y) {
|
||||
|
||||
M.mod_assign.init_grading_options = function(Y) {
|
||||
Y.use('node', function(Y) {
|
||||
var paginationelement = Y.one('#id_perpage');
|
||||
paginationelement.on('change', function(e) {
|
||||
Y.one('form.gradingoptionsform').submit();
|
||||
});
|
||||
var markerfilterelement = Y.one('#id_markerfilter');
|
||||
if (markerfilterelement) {
|
||||
markerfilterelement.on('change', function(e) {
|
||||
|
||||
@@ -54,13 +54,9 @@ class mod_assign_quick_grading_form extends moodleform {
|
||||
$mform->addElement('hidden', 'lastpage', $instance['page']);
|
||||
$mform->setType('lastpage', PARAM_INT);
|
||||
|
||||
// Skip notifications option.
|
||||
$mform->addElement('selectyesno', 'sendstudentnotifications', get_string('sendstudentnotifications', 'assign'));
|
||||
$mform->setDefault('sendstudentnotifications', $instance['sendstudentnotifications']);
|
||||
|
||||
// Buttons.
|
||||
$savemessage = get_string('saveallquickgradingchanges', 'assign');
|
||||
$mform->addElement('submit', 'savequickgrades', $savemessage);
|
||||
// No need to add a submit button.
|
||||
// The submit button is in the footer.
|
||||
$mform->addElement('html', $instance['footer']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,14 +135,6 @@
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.path-mod-assign .gradingbatchoperationsform {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.path-mod-assign.jsenabled .gradingbatchoperationsform {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.path-mod-assign .gradingtable table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_assign/bulkactions/grading/bulk_action_modal_body
|
||||
|
||||
Renders the body of the bulk action confirmation modal.
|
||||
|
||||
Context variables required for this template:
|
||||
* text - The bulk action confirmation text.
|
||||
* operation - The name of the bulk operation.
|
||||
* cmid - The course module ID.
|
||||
* selectedusers - The string containing the IDs of the selected users.
|
||||
* sesskey - The session key.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"text": "Lock all selected submissions?",
|
||||
"operation": "lock",
|
||||
"cmid": 2,
|
||||
"selectedusers": "3,5",
|
||||
"sesskey": "abc123"
|
||||
}
|
||||
}}
|
||||
<p>{{text}}</p>
|
||||
<form method="post" action="view.php">
|
||||
<input type="hidden" name="action" value="gradingbatchoperation">
|
||||
<input type="hidden" name="operation" value="{{operation}}">
|
||||
<input type="hidden" name="id" value="{{cmid}}">
|
||||
<input type="hidden" name="selectedusers" value="{{selectedusers}}">
|
||||
<input type="hidden" name="sesskey" value="{{{sesskey}}}">
|
||||
<input type="hidden" name="returnaction" value="grading">
|
||||
</form>
|
||||
@@ -0,0 +1,36 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_assign/bulkactions/grading/bulk_delete_trigger
|
||||
|
||||
Renders the bulk delete trigger element in assignment grading page.
|
||||
|
||||
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,
|
||||
"isfirst": true
|
||||
}
|
||||
}}
|
||||
{{< core/bulkactions/bulk_action_trigger }}
|
||||
{{$action}}removesubmission{{/action}}
|
||||
{{$title}}{{#str}} batchoperationremovesubmission, mod_assign {{/str}}{{/title}}
|
||||
{{$icon}}{{#pix}} i/delete, core {{/pix}}{{/icon}}
|
||||
{{/ core/bulkactions/bulk_action_trigger }}
|
||||
@@ -0,0 +1,36 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_assign/bulkactions/grading/bulk_extend_trigger
|
||||
|
||||
Renders the bulk extend trigger element in assignment grading page.
|
||||
|
||||
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,
|
||||
"isfirst": true
|
||||
}
|
||||
}}
|
||||
{{< core/bulkactions/bulk_action_trigger }}
|
||||
{{$action}}grantextension{{/action}}
|
||||
{{$title}}{{#str}} batchoperationgrantextension, mod_assign {{/str}}{{/title}}
|
||||
{{$icon}}{{#pix}} i/duration, core {{/pix}}{{/icon}}
|
||||
{{/ core/bulkactions/bulk_action_trigger }}
|
||||
@@ -0,0 +1,42 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_assign/bulkactions/grading/bulk_general_action_trigger
|
||||
|
||||
Renders the general bulk action trigger element in assignment grading page.
|
||||
|
||||
Context variables required for this template:
|
||||
* action: The action to be performed.
|
||||
* 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": "<i class=\"icon fa fa-lock fa-fw\"></i>",
|
||||
"showindropdown": false,
|
||||
"isfirst": true
|
||||
}
|
||||
}}
|
||||
{{< core/bulkactions/bulk_action_trigger }}
|
||||
{{$action}}{{action}}{{/action}}
|
||||
{{$title}}{{title}}{{/title}}
|
||||
{{$icon}}{{{icon}}}{{/icon}}
|
||||
{{/ core/bulkactions/bulk_action_trigger }}
|
||||
@@ -0,0 +1,36 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_assign/bulkactions/grading/bulk_message_trigger
|
||||
|
||||
Renders the bulk message trigger element in assignment grading page.
|
||||
|
||||
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,
|
||||
"isfirst": true
|
||||
}
|
||||
}}
|
||||
{{< core/bulkactions/bulk_action_trigger }}
|
||||
{{$action}}message{{/action}}
|
||||
{{$title}}{{#str}} message, core {{/str}}{{/title}}
|
||||
{{$icon}}{{#pix}} t/message, core {{/pix}}{{/icon}}
|
||||
{{/ core/bulkactions/bulk_action_trigger }}
|
||||
@@ -0,0 +1,36 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_assign/bulkactions/grading/bulk_setmarkingallocation_trigger
|
||||
|
||||
Renders the bulk set allocated marker trigger element in assignment grading page.
|
||||
|
||||
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,
|
||||
"isfirst": true
|
||||
}
|
||||
}}
|
||||
{{< core/bulkactions/bulk_action_trigger }}
|
||||
{{$action}}setmarkingallocation{{/action}}
|
||||
{{$title}}{{#str}} batchoperationsetmarkingallocation, mod_assign {{/str}}{{/title}}
|
||||
{{$icon}}<i class="icon fa fa-pen-to-square fa-fw"></i>{{/icon}}
|
||||
{{/ core/bulkactions/bulk_action_trigger }}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_assign/bulkactions/grading/bulk_setmarkingworkflowstate_trigger
|
||||
|
||||
Renders the bulk set marking workflow state trigger element in assignment grading page.
|
||||
|
||||
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,
|
||||
"isfirst": true
|
||||
}
|
||||
}}
|
||||
{{< core/bulkactions/bulk_action_trigger }}
|
||||
{{$action}}setmarkingworkflowstate{{/action}}
|
||||
{{$title}}{{#str}} batchoperationsetmarkingworkflowstate, mod_assign {{/str}}{{/title}}
|
||||
{{$icon}}<i class="icon fa fa-diagram-project fa-fw"></i>{{/icon}}
|
||||
{{/ core/bulkactions/bulk_action_trigger }}
|
||||
@@ -0,0 +1,48 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_assign/grading_paging_selector
|
||||
|
||||
Template for pagination dropdown on the assignment grading page.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"baseurl": "http://example.com/grading.php?id=1",
|
||||
"options": [
|
||||
{"name": "10", "value": "10", "selected": false},
|
||||
{"name": "20", "value": "20", "selected": false},
|
||||
{"name": "50", "value": "50", "selected": true},
|
||||
{"name": "All", "value": "-1", "selected": false}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<label>
|
||||
{{#str}}show{{/str}}
|
||||
<select name="perpage" class="mt-1 custom-select ignoredirty" id="{{uniqid}}-perpage">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
</select>
|
||||
</label>
|
||||
{{#js}}
|
||||
document.getElementById('{{uniqid}}-perpage').addEventListener('change', function(e) {
|
||||
var url = new URL('{{{baseurl}}}');
|
||||
url.searchParams.set('perpage', e.target.value);
|
||||
|
||||
window.location.href = url;
|
||||
});
|
||||
{{/js}}
|
||||
@@ -0,0 +1,53 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_assign/grading_sticky_footer
|
||||
|
||||
Sticky footer template for the assignment grading page.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"perpage": "<label>Show<select name='perpage' class='custom-select'><option value='-1'>All</select></label>",
|
||||
"pagingbar": "<nav class='pagination pagination-centered justify-content-center'><ul class='mt-1 pagination '><li class='page-item active'><a href='#' class='page-link'><span>1</span></a></li></ul></nav>",
|
||||
"hassubmit": true,
|
||||
"sendstudentnotifications": true
|
||||
}
|
||||
}}
|
||||
<div class="col-auto">
|
||||
{{#perpage}}
|
||||
{{{.}}}
|
||||
{{/perpage}}
|
||||
</div>
|
||||
<div class="col">
|
||||
{{#pagingbar}}
|
||||
{{{.}}}
|
||||
{{/pagingbar}}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
{{#hassubmit}}
|
||||
<div class="d-flex align-items-center" data-region="quick-grading-save">
|
||||
<div class="me-4">
|
||||
<input type="hidden" name="sendstudentnotifications" value="0" {{#sendstudentnotifications}}disabled{{/sendstudentnotifications}}>
|
||||
<input type="checkbox" id="send-student-notifications-{{uniqid}}" name="sendstudentnotifications" {{#sendstudentnotifications}}checked="checked"{{/sendstudentnotifications}}>
|
||||
<label for="send-student-notifications-{{uniqid}}" class="m-0">{{#str}} notifystudents, mod_assign {{/str}}</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{#str}}save{{/str}}
|
||||
</button>
|
||||
</div>
|
||||
{{/hassubmit}}
|
||||
</div>
|
||||
@@ -107,15 +107,13 @@ Feature: In an assignment, students start a new attempt based on their previous
|
||||
And "Student 3" row "Status" column of "generaltable" table should contain "No submission"
|
||||
And "Student 4" row "Status" column of "generaltable" table should contain "No submission"
|
||||
And I click on "Quick grading" "checkbox"
|
||||
And I click on "Student 1" "checkbox"
|
||||
And I set the field "User grade" to "60.0"
|
||||
And I press "Save all quick grading changes"
|
||||
And I click on "Save" "button" in the "sticky-footer" "region"
|
||||
And I should see "The grade changes were saved"
|
||||
And I press "Continue"
|
||||
And I click on "Student 1" "checkbox"
|
||||
And I set the following fields to these values:
|
||||
| operation | Allow another attempt |
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I click on "Grant attempt" "button" in the "sticky-footer" "region"
|
||||
And I click on "Grant attempt" "button" in the "Allow another attempt" "dialogue"
|
||||
And I should not see "The grades were not saved because someone has modified one or more records more recently than when you loaded the page."
|
||||
And I log out
|
||||
And I am on the "Test assignment name" Activity page logged in as student3
|
||||
|
||||
@@ -67,8 +67,8 @@ Feature: Bulk released grades should not be sent to gradebook while submissions
|
||||
@javascript @_alert
|
||||
Scenario: Grades are released in bulk before student identities are revealed.
|
||||
When I set the field "selectall" to "1"
|
||||
And I set the field "operation" to "Set marking workflow state"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I click on "Change marking state" "button" in the "sticky-footer" "region"
|
||||
And I click on "Change marking state" "button" in the "Set marking workflow state" "dialogue"
|
||||
Then I should not see "Student 1 (student1@example.com)"
|
||||
And I should not see "Student 2 (student2@example.com)"
|
||||
And I set the field "Marking workflow state" to "Released"
|
||||
@@ -102,8 +102,8 @@ Feature: Bulk released grades should not be sent to gradebook while submissions
|
||||
When I choose the "Reveal student identities" item in the "Actions" action menu
|
||||
And I press "Continue"
|
||||
When I set the field "selectall" to "1"
|
||||
And I set the field "operation" to "Set marking workflow state"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I click on "Change marking state" "button" in the "sticky-footer" "region"
|
||||
And I click on "Change marking state" "button" in the "Set marking workflow state" "dialogue"
|
||||
Then I should see "Student 1 (student1@example.com)"
|
||||
And I should see "Student 2 (student2@example.com)"
|
||||
And I set the field "Marking workflow state" to "Released"
|
||||
@@ -128,8 +128,8 @@ Feature: Bulk released grades should not be sent to gradebook while submissions
|
||||
And I press "Save and display"
|
||||
And I navigate to "Submissions" in current page administration
|
||||
When I set the field "selectall" to "1"
|
||||
And I set the field "operation" to "Set marking workflow state"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I click on "Change marking state" "button" in the "sticky-footer" "region"
|
||||
And I click on "Change marking state" "button" in the "Set marking workflow state" "dialogue"
|
||||
Then I should not see "Student 1 (student1@example.com)"
|
||||
And I should not see "Student 2 (student2@example.com)"
|
||||
And I set the field "Marking workflow state" to "Released"
|
||||
|
||||
@@ -45,8 +45,8 @@ Feature: Bulk remove submissions
|
||||
And I should see "I'm the student1 submission"
|
||||
And I should see "I'm the student2 submission"
|
||||
And I set the field "selectall" to "1"
|
||||
When I set the field "operation" to "Remove submission"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I click on "Delete" "button" in the "sticky-footer" "region"
|
||||
And I click on "Delete" "button" in the "Remove submission" "dialogue"
|
||||
Then I should not see "I'm the student1 submission"
|
||||
And I should not see "I'm the student2 submission"
|
||||
And I log out
|
||||
@@ -78,7 +78,7 @@ Feature: Bulk remove submissions
|
||||
And I should see "I'm the student1 submission"
|
||||
And I should see "I'm the student2 submission"
|
||||
And I set the field "selectall" to "1"
|
||||
Then I should not see "Remove submission" in the "Choose operation" "select"
|
||||
Then I should not see "Delete" in the "sticky-footer" "region"
|
||||
|
||||
@javascript @skip_chrome_zerosize
|
||||
Scenario: Bulk remove submission when shared group users are added to the bulk
|
||||
@@ -111,8 +111,8 @@ Feature: Bulk remove submissions
|
||||
And I should see "I'm the student2 submission"
|
||||
And I should not see "I'm the student3 submission"
|
||||
And I set the field "selectall" to "1"
|
||||
When I set the field "operation" to "Remove submission"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
When I click on "Delete" "button" in the "sticky-footer" "region"
|
||||
And I click on "Delete" "button" in the "Remove submission" "dialogue"
|
||||
|
||||
Then I should not see "I'm the student1 submission"
|
||||
Then I should not see "I'm the student2 submission"
|
||||
@@ -147,8 +147,8 @@ Feature: Bulk remove submissions
|
||||
And I should see "I'm the student2 submission"
|
||||
And I should see "I'm the student3 submission"
|
||||
And I set the field "selectall" to "1"
|
||||
When I set the field "operation" to "Remove submission"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
When I click on "Delete" "button" in the "sticky-footer" "region"
|
||||
And I click on "Delete" "button" in the "Remove submission" "dialogue"
|
||||
Then I should not see "I'm the student1 submission"
|
||||
And I should not see "I'm the student2 submission"
|
||||
And I should not see "I'm the student3 submission"
|
||||
|
||||
@@ -53,8 +53,8 @@ Feature: Grant an extension to an offline student
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Submissions" in current page administration
|
||||
And I set the field "selectall" to "1"
|
||||
And I set the field "operation" to "Grant extension"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I click on "Extend" "button" in the "sticky-footer" "region"
|
||||
And I click on "Extend" "button" in the "Grant extension" "dialogue"
|
||||
And I should see "Student 1 (student1@example.com)"
|
||||
And I should see "Student 2 (student2@example.com)"
|
||||
And I should see "Student 3 (student3@example.com)"
|
||||
@@ -102,8 +102,8 @@ Feature: Grant an extension to an offline student
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Submissions" in current page administration
|
||||
And I set the field "selectall" to "1"
|
||||
And I set the field "operation" to "Grant extension"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I click on "Extend" "button" in the "sticky-footer" "region"
|
||||
And I click on "Extend" "button" in the "Grant extension" "dialogue"
|
||||
And I should see "Student 1 (student1@example.com)"
|
||||
And I should see "Student 2 (student2@example.com)"
|
||||
And I should see "Student 3 (student3@example.com)"
|
||||
|
||||
@@ -80,7 +80,8 @@ Feature: Prevent or allow assignment submission changes
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Submissions" in current page administration
|
||||
And I set the field "selectall" to "1"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I click on "Lock" "button" in the "sticky-footer" "region"
|
||||
And I click on "Lock" "button" in the "Lock submissions" "dialogue"
|
||||
Then I should see "Submission changes not allowed" in the "Student 1" "table_row"
|
||||
And I should see "Submission changes not allowed" in the "Student 2" "table_row"
|
||||
And I log out
|
||||
@@ -92,8 +93,8 @@ Feature: Prevent or allow assignment submission changes
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "Submissions" in current page administration
|
||||
And I set the field "selectall" to "1"
|
||||
And I set the field "id_operation" to "Unlock submissions"
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I click on "Unlock" "button" in the "sticky-footer" "region"
|
||||
And I click on "Unlock" "button" in the "Unlock submissions" "dialogue"
|
||||
And I should not see "Submission changes not allowed" in the "Student 1" "table_row"
|
||||
And I should not see "Submission changes not allowed" in the "Student 2" "table_row"
|
||||
And I log out
|
||||
|
||||
@@ -95,7 +95,7 @@ Feature: In an assignment, teachers grade multiple students on one page
|
||||
And I follow "View all submissions"
|
||||
Then I click on "Quick grading" "checkbox"
|
||||
And I set the field "User grade" to "60.0"
|
||||
And I press "Save all quick grading changes"
|
||||
And I click on "Save" "button" in the "sticky-footer" "region"
|
||||
And I should see "The grade changes were saved"
|
||||
And I press "Continue"
|
||||
And I am on the "Test assignment name" "assign activity" page logged in as student1
|
||||
@@ -123,7 +123,7 @@ Feature: In an assignment, teachers grade multiple students on one page
|
||||
And I click on "Hide Feedback comments" "link"
|
||||
And I click on "Hide Final grade" "link"
|
||||
And I click on "Hide Outcomes" "link"
|
||||
And I press "Save all quick grading changes"
|
||||
And I click on "Save" "button" in the "sticky-footer" "region"
|
||||
And I should see "The grade changes were saved"
|
||||
And I press "Continue"
|
||||
And I am on the "Test assignment name" "assign activity" page logged in as student1
|
||||
|
||||
@@ -42,7 +42,7 @@ Feature: Submissions are unlocked when a new attempt is given
|
||||
And I should see "Submission changes not allowed"
|
||||
And I click on "Quick grading" "checkbox"
|
||||
And I set the field "User grade" to "49.0"
|
||||
And I press "Save all quick grading changes"
|
||||
And I click on "Save" "button" in the "sticky-footer" "region"
|
||||
And I should see "The grade changes were saved"
|
||||
And I press "Continue"
|
||||
Then I should see "Reopened"
|
||||
|
||||
+4
-33
@@ -117,44 +117,15 @@ class mod_assign_testable_assign extends assign {
|
||||
public function testable_view_batch_set_workflow_state($selectedusers) {
|
||||
global $PAGE;
|
||||
$PAGE->set_url('/mod/assign/view.php');
|
||||
$mform = $this->testable_grading_batch_operations_form('setmarkingworkflowstate', $selectedusers);
|
||||
return parent::view_batch_set_workflow_state($mform);
|
||||
$_POST['selectedusers'] = $selectedusers;
|
||||
return parent::view_batch_set_workflow_state();
|
||||
}
|
||||
|
||||
public function testable_view_batch_markingallocation($selectedusers) {
|
||||
global $PAGE;
|
||||
$PAGE->set_url('/mod/assign/view.php');
|
||||
$mform = $this->testable_grading_batch_operations_form('setmarkingallocation', $selectedusers);
|
||||
return parent::view_batch_markingallocation($mform);
|
||||
}
|
||||
|
||||
public function testable_grading_batch_operations_form($operation, $selectedusers) {
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/gradingbatchoperationsform.php');
|
||||
|
||||
// Mock submit the grading operations form.
|
||||
$data = array();
|
||||
$data['id'] = $this->get_course_module()->id;
|
||||
$data['selectedusers'] = $selectedusers;
|
||||
$data['returnaction'] = 'grading';
|
||||
$data['operation'] = $operation;
|
||||
mod_assign_grading_batch_operations_form::mock_submit($data);
|
||||
|
||||
// Set required variables in the form.
|
||||
$formparams = array();
|
||||
$formparams['submissiondrafts'] = 1;
|
||||
$formparams['duedate'] = 1;
|
||||
$formparams['maxattempts'] = ASSIGN_UNLIMITED_ATTEMPTS;
|
||||
$formparams['attemptreopenmethod'] = ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL;
|
||||
$formparams['feedbackplugins'] = array();
|
||||
$formparams['markingworkflow'] = 1;
|
||||
$formparams['markingallocation'] = 1;
|
||||
$formparams['cm'] = $this->get_course_module()->id;
|
||||
$formparams['context'] = $this->get_context();
|
||||
$mform = new mod_assign_grading_batch_operations_form(null, $formparams);
|
||||
|
||||
return $mform;
|
||||
$_POST['selectedusers'] = $selectedusers;
|
||||
return parent::view_batch_markingallocation();
|
||||
}
|
||||
|
||||
public function testable_update_activity_completion_records($teamsubmission,
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+56
-29
@@ -107,7 +107,7 @@ const dropdownFix = () => {
|
||||
// Search for menu items by finding the first item that has
|
||||
// text starting with the typed character (case insensitive).
|
||||
document.addEventListener('keypress', e => {
|
||||
if (e.target.matches('.dropdown [role="menu"] [role="menuitem"]')) {
|
||||
if (e.target.matches('[role="menu"] [role="menuitem"]')) {
|
||||
const menu = e.target.closest('[role="menu"]');
|
||||
if (!menu) {
|
||||
return;
|
||||
@@ -139,7 +139,7 @@ const dropdownFix = () => {
|
||||
handleMenuButton(e);
|
||||
}
|
||||
|
||||
if (e.target.matches('.dropdown [role="menu"] [role="menuitem"]')) {
|
||||
if (e.target.matches('[role="menu"] [role="menuitem"]')) {
|
||||
const trigger = e.key;
|
||||
let next = false;
|
||||
const menu = e.target.closest('[role="menu"]');
|
||||
@@ -193,8 +193,9 @@ const dropdownFix = () => {
|
||||
}
|
||||
});
|
||||
|
||||
$('.dropdown').on('shown.bs.dropdown', e => {
|
||||
const dialog = e.target.querySelector(`#${e.relatedTarget.getAttribute('aria-controls')}[role="dialog"]`);
|
||||
// Trap focus if the dropdown is a dialog.
|
||||
$(document).on('shown.bs.dropdown', e => {
|
||||
const dialog = e.target.querySelector('.dropdown-menu[role="dialog"]');
|
||||
if (dialog) {
|
||||
// Use setTimeout to make sure the dialog is positioned correctly to prevent random scrolling.
|
||||
setTimeout(() => {
|
||||
@@ -203,8 +204,9 @@ const dropdownFix = () => {
|
||||
}
|
||||
});
|
||||
|
||||
$('.dropdown').on('hidden.bs.dropdown', e => {
|
||||
const dialog = e.target.querySelector(`#${e.relatedTarget.getAttribute('aria-controls')}[role="dialog"]`);
|
||||
// Untrap focus when the dialog dropdown is closed.
|
||||
$(document).on('hidden.bs.dropdown', e => {
|
||||
const dialog = e.target.querySelector('.dropdown-menu[role="dialog"]');
|
||||
if (dialog) {
|
||||
FocusLockManager.untrapFocus();
|
||||
}
|
||||
@@ -414,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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -465,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);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -500,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();
|
||||
};
|
||||
|
||||
@@ -15,7 +15,6 @@ body {
|
||||
bottom: calc(#{$stickyfooter-height} * -1);
|
||||
transition: bottom .5s;
|
||||
z-index: $zindex-fixed;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 1rem rgba($black, .15);
|
||||
font-size: calc(#{$font-size-base} * 1.10);
|
||||
// Adjust sticky footer width to the main content area.
|
||||
|
||||
@@ -36632,7 +36632,6 @@ body {
|
||||
bottom: calc(max(80px, 0.9375rem * 3) * -1);
|
||||
transition: bottom 0.5s;
|
||||
z-index: 1030;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.15);
|
||||
font-size: calc(0.9375rem * 1.10);
|
||||
}
|
||||
|
||||
@@ -36566,7 +36566,6 @@ body {
|
||||
bottom: calc(max(80px, 0.9375rem * 3) * -1);
|
||||
transition: bottom 0.5s;
|
||||
z-index: 1030;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.15);
|
||||
font-size: calc(0.9375rem * 1.10);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user