diff --git a/user/amd/build/local/participants/bulkactions.min.js b/user/amd/build/local/participants/bulkactions.min.js new file mode 100644 index 00000000000..90f87b3499a --- /dev/null +++ b/user/amd/build/local/participants/bulkactions.min.js @@ -0,0 +1,2 @@ +function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("core_user/local/participants/bulkactions",["exports","core_user/repository","core/str","core/modal_events","core/modal_factory","core/templates","core/toast"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.showSendMessage=a.showAddNote=void 0;b=j(b);c=j(c);d=h(d);e=h(e);f=h(f);function h(a){return a&&a.__esModule?a:{default:a}}function i(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;i=function(){return a};return a}function j(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=i();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}var k=function(a,b,g,h){if(!b.length){return Promise.resolve()}var i=[];for(var m in g){switch(m){case"draft":i.push({value:"personal",label:g[m]});break;case"public":i.push({value:"course",label:g[m],selected:1});break;case"site":i.push({value:m,label:g[m]});break;}}var j={stateNames:i,stateHelpIcon:h.innerHTML},k=null;if(1===b.length){k=c.get_string("addbulknotesingle","core_notes")}else{k=c.get_string("addbulknote","core_notes",b.length)}return e.default.create({type:e.default.types.SAVE_CANCEL,body:f.default.render("core_user/add_bulk_note",j),title:k,buttons:{save:k},removeOnClose:!0}).then(function(c){c.getRoot().on(d.default.save,function(){return l(a,b,c)});c.show();return c})};a.showAddNote=k;var l=function(a,d,e){var f=e.getRoot().find("form textarea").val(),h=e.getRoot().find("form select").val(),i=d.map(function(b){return{userid:b,text:f,courseid:a,publishstate:h}});return b.createNotesForUsers(i).then(function(a){if(1===a.length){return c.get_string("addbulknotedonesingle","core_notes")}else{return c.get_string("addbulknotedone","core_notes",a.length)}}).then(function(a){return(0,g.add)(a)}).catch(Notification.exception)},m=function(a){if(!a.length){return Promise.resolve()}var b;if(1===a.length){b=c.get_string("sendbulkmessagesingle","core_message")}else{b=c.get_string("sendbulkmessage","core_message",a.length)}return e.default.create({type:e.default.types.SAVE_CANCEL,body:f.default.render("core_user/send_bulk_message",{}),title:b,buttons:{save:b},removeOnClose:!0}).then(function(b){b.getRoot().on(d.default.save,function(){n(b,a)});b.show();return b})};a.showSendMessage=m;var n=function(a,d){var e=a.getRoot().find("form textarea").val(),f=d.map(function(a){return{touserid:a,text:e}});return b.sendMessagesToUsers(f).then(function(a){if(1==a.length){return c.get_string("sendbulkmessagesentsingle","core_message")}else{return c.get_string("sendbulkmessagesent","core_message",a.length)}}).then(function(a){return(0,g.add)(a)}).catch(Notification.exception)}}); +//# sourceMappingURL=bulkactions.min.js.map diff --git a/user/amd/build/local/participants/bulkactions.min.js.map b/user/amd/build/local/participants/bulkactions.min.js.map new file mode 100644 index 00000000000..c09406ff260 --- /dev/null +++ b/user/amd/build/local/participants/bulkactions.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/local/participants/bulkactions.js"],"names":["showAddNote","courseid","users","noteStateNames","stateHelpIcon","length","Promise","resolve","states","key","push","value","label","selected","context","stateNames","innerHTML","titlePromise","Str","get_string","ModalFactory","create","type","types","SAVE_CANCEL","body","Templates","render","title","buttons","save","removeOnClose","then","modal","getRoot","on","ModalEvents","submitAddNote","show","text","find","val","publishstate","notes","map","userid","Repository","createNotesForUsers","noteIds","msg","catch","Notification","exception","showSendMessage","submitSendMessage","messages","touserid","sendMessagesToUsers","messageIds"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Bulk actions for lists of participants.\n *\n * @module core_user/local/participants/bulkactions\n * @package core_user\n * @copyright 2020 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as Repository from 'core_user/repository';\nimport * as Str from 'core/str';\nimport ModalEvents from 'core/modal_events';\nimport ModalFactory from 'core/modal_factory';\nimport Templates from 'core/templates';\nimport {add as notifyUser} from 'core/toast';\n\n/**\n * Show the add note popup\n *\n * @param {Number} courseid\n * @param {Number[]} users\n * @param {String[]} noteStateNames\n * @param {HTMLElement} stateHelpIcon\n * @return {Promise}\n */\nexport const showAddNote = (courseid, users, noteStateNames, stateHelpIcon) => {\n if (!users.length) {\n // No users were selected.\n return Promise.resolve();\n }\n\n const states = [];\n for (let key in noteStateNames) {\n switch (key) {\n case 'draft':\n states.push({value: 'personal', label: noteStateNames[key]});\n break;\n case 'public':\n states.push({value: 'course', label: noteStateNames[key], selected: 1});\n break;\n case 'site':\n states.push({value: key, label: noteStateNames[key]});\n break;\n }\n }\n\n const context = {\n stateNames: states,\n stateHelpIcon: stateHelpIcon.innerHTML,\n };\n\n let titlePromise = null;\n if (users.length === 1) {\n titlePromise = Str.get_string('addbulknotesingle', 'core_notes');\n } else {\n titlePromise = Str.get_string('addbulknote', 'core_notes', users.length);\n }\n\n return ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n body: Templates.render('core_user/add_bulk_note', context),\n title: titlePromise,\n buttons: {\n save: titlePromise,\n },\n removeOnClose: true,\n })\n .then(modal => {\n modal.getRoot().on(ModalEvents.save, () => submitAddNote(courseid, users, modal));\n\n modal.show();\n\n return modal;\n });\n};\n\n/**\n * Add a note to this list of users.\n *\n * @param {Number} courseid\n * @param {Number[]} users\n * @param {Modal} modal\n * @return {Promise}\n */\nconst submitAddNote = (courseid, users, modal) => {\n const text = modal.getRoot().find('form textarea').val();\n const publishstate = modal.getRoot().find('form select').val();\n\n const notes = users.map(userid => {\n return {\n userid,\n text,\n courseid,\n publishstate,\n };\n });\n\n return Repository.createNotesForUsers(notes)\n .then(noteIds => {\n if (noteIds.length === 1) {\n return Str.get_string('addbulknotedonesingle', 'core_notes');\n } else {\n return Str.get_string('addbulknotedone', 'core_notes', noteIds.length);\n }\n })\n .then(msg => notifyUser(msg))\n .catch(Notification.exception);\n};\n\n/**\n * Show the send message popup.\n *\n * @param {Number[]} users\n * @return {Promise}\n */\nexport const showSendMessage = users => {\n if (!users.length) {\n // Nothing to do.\n return Promise.resolve();\n }\n\n let titlePromise;\n if (users.length === 1) {\n titlePromise = Str.get_string('sendbulkmessagesingle', 'core_message');\n } else {\n titlePromise = Str.get_string('sendbulkmessage', 'core_message', users.length);\n }\n\n return ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n body: Templates.render('core_user/send_bulk_message', {}),\n title: titlePromise,\n buttons: {\n save: titlePromise,\n },\n removeOnClose: true,\n })\n .then(modal => {\n modal.getRoot().on(ModalEvents.save, () => {\n submitSendMessage(modal, users);\n });\n\n modal.show();\n\n return modal;\n });\n};\n\n/**\n * Send a message to these users.\n *\n * @param {Modal} modal\n * @param {Number[]} users\n * @return {Promise}\n */\nconst submitSendMessage = (modal, users) => {\n const text = modal.getRoot().find('form textarea').val();\n\n const messages = users.map(touserid => {\n return {\n touserid,\n text,\n };\n });\n\n return Repository.sendMessagesToUsers(messages)\n .then(messageIds => {\n if (messageIds.length == 1) {\n return Str.get_string('sendbulkmessagesentsingle', 'core_message');\n } else {\n return Str.get_string('sendbulkmessagesent', 'core_message', messageIds.length);\n }\n })\n .then(msg => notifyUser(msg))\n .catch(Notification.exception);\n};\n"],"file":"bulkactions.min.js"} \ No newline at end of file diff --git a/user/amd/build/participants.min.js b/user/amd/build/participants.min.js index 56be84f842b..f433003ac95 100644 --- a/user/amd/build/participants.min.js +++ b/user/amd/build/participants.min.js @@ -1,2 +1,2 @@ -define ("core_user/participants",["jquery","core/str","core/modal_factory","core/modal_events","core/templates","core/notification","core/ajax","core/custom_interaction_events"],function(a,b,c,d,e,f,g,h){var i={BULKACTIONSELECT:"#formactionid",BULKUSERCHECKBOXES:"input.usercheckbox",BULKUSERNOSCHECKBOXES:"input.usercheckbox[value='0']",BULKUSERSELECTEDCHECKBOXES:"input.usercheckbox:checked",BULKACTIONFORM:"#participantsform",CHECKALLBUTTON:"#checkall",CHECKALLNOSBUTTON:"#checkallnos"},j=function(a){this.courseId=a.courseid;this.noteStateNames=a.noteStateNames;this.stateHelpIcon=a.stateHelpIcon;this.attachEventListeners()};j.prototype.modal=null;j.prototype.courseId=-1;j.prototype.noteStateNames={};j.prototype.stateHelpIcon="";j.prototype.attachEventListeners=function(){h.define(i.BULKACTIONSELECT,[h.events.accessibleChange]);a(i.BULKACTIONSELECT).on(h.events.accessibleChange,function(b){var c=a(b.target).val();if(-1!==c.indexOf("#")){b.preventDefault();var d=[];a(i.BULKUSERSELECTEDCHECKBOXES).each(function(b,c){var e=a(c).attr("name"),f=e.replace("user","");d.push(f)});if("#messageselect"==c){this.showSendMessage(d).fail(f.exception)}else if("#addgroupnote"==c){this.showAddNote(d).fail(f.exception)}a(i.BULKACTIONSELECT+" option[value=\"\"]").prop("selected","selected")}else if(""!==c){if(0.\n\n/**\n * Some UI stuff for participants page.\n * This is also used by the report/participants/index.php because it has the same functionality.\n *\n * @module core_user/participants\n * @package core_user\n * @copyright 2017 Damyon Wiese\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/templates', 'core/notification', 'core/ajax',\n 'core/custom_interaction_events'],\n function($, Str, ModalFactory, ModalEvents, Templates, Notification, Ajax, CustomEvents) {\n\n var SELECTORS = {\n BULKACTIONSELECT: \"#formactionid\",\n BULKUSERCHECKBOXES: \"input.usercheckbox\",\n BULKUSERNOSCHECKBOXES: \"input.usercheckbox[value='0']\",\n BULKUSERSELECTEDCHECKBOXES: \"input.usercheckbox:checked\",\n BULKACTIONFORM: \"#participantsform\",\n CHECKALLBUTTON: \"#checkall\",\n CHECKALLNOSBUTTON: \"#checkallnos\"\n };\n\n /**\n * Constructor\n *\n * @param {Object} options Object containing options. Contextid is required.\n * Each call to templates.render gets it's own instance of this class.\n */\n var Participants = function(options) {\n\n this.courseId = options.courseid;\n this.noteStateNames = options.noteStateNames;\n this.stateHelpIcon = options.stateHelpIcon;\n\n this.attachEventListeners();\n };\n // Class variables and functions.\n\n /**\n * @var {Modal} modal\n * @private\n */\n Participants.prototype.modal = null;\n\n /**\n * @var {int} courseId\n * @private\n */\n Participants.prototype.courseId = -1;\n\n /**\n * @var {Object} noteStateNames\n * @private\n */\n Participants.prototype.noteStateNames = {};\n\n /**\n * @var {String} stateHelpIcon\n * @private\n */\n Participants.prototype.stateHelpIcon = \"\";\n\n /**\n * Private method\n *\n * @method attachEventListeners\n * @private\n */\n Participants.prototype.attachEventListeners = function() {\n CustomEvents.define(SELECTORS.BULKACTIONSELECT, [CustomEvents.events.accessibleChange]);\n $(SELECTORS.BULKACTIONSELECT).on(CustomEvents.events.accessibleChange, function(e) {\n var action = $(e.target).val();\n if (action.indexOf('#') !== -1) {\n e.preventDefault();\n\n var ids = [];\n $(SELECTORS.BULKUSERSELECTEDCHECKBOXES).each(function(index, ele) {\n var name = $(ele).attr('name');\n var id = name.replace('user', '');\n ids.push(id);\n });\n\n if (action == '#messageselect') {\n this.showSendMessage(ids).fail(Notification.exception);\n } else if (action == '#addgroupnote') {\n this.showAddNote(ids).fail(Notification.exception);\n }\n $(SELECTORS.BULKACTIONSELECT + ' option[value=\"\"]').prop('selected', 'selected');\n } else if (action !== '') {\n if ($(SELECTORS.BULKUSERSELECTEDCHECKBOXES).length > 0) {\n $(SELECTORS.BULKACTIONFORM).submit();\n } else {\n $(SELECTORS.BULKACTIONSELECT + ' option[value=\"\"]').prop('selected', 'selected');\n }\n }\n }.bind(this));\n\n $(SELECTORS.CHECKALLBUTTON).on('click', function() {\n var showallink = $(this).data('showallink');\n if (showallink) {\n window.location = showallink;\n }\n });\n\n $(SELECTORS.CHECKALLNOSBUTTON).on('click', function() {\n $(SELECTORS.BULKUSERNOSCHECKBOXES).prop('checked', true);\n });\n };\n\n /**\n * Show the add note popup\n *\n * @method showAddNote\n * @private\n * @param {int[]} users\n * @return {Promise}\n */\n Participants.prototype.showAddNote = function(users) {\n\n if (users.length == 0) {\n // Nothing to do.\n return $.Deferred().resolve().promise();\n }\n\n var states = [];\n for (var key in this.noteStateNames) {\n switch (key) {\n case 'draft':\n states.push({value: 'personal', label: this.noteStateNames[key]});\n break;\n case 'public':\n states.push({value: 'course', label: this.noteStateNames[key], selected: 1});\n break;\n case 'site':\n states.push({value: key, label: this.noteStateNames[key]});\n break;\n }\n }\n\n var context = {stateNames: states, stateHelpIcon: this.stateHelpIcon};\n var titlePromise = null;\n if (users.length == 1) {\n titlePromise = Str.get_string('addbulknotesingle', 'core_notes');\n } else {\n titlePromise = Str.get_string('addbulknote', 'core_notes', users.length);\n }\n\n return $.when(\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n body: Templates.render('core_user/add_bulk_note', context)\n }),\n titlePromise\n ).then(function(modal, title) {\n // Keep a reference to the modal.\n this.modal = modal;\n this.modal.setTitle(title);\n this.modal.setSaveButtonText(title);\n\n // We want to focus on the action select when the dialog is closed.\n this.modal.getRoot().on(ModalEvents.hidden, function() {\n var notification = $('#user-notifications [role=alert]');\n if (notification.length) {\n notification.focus();\n } else {\n $(SELECTORS.BULKACTIONSELECT).focus();\n }\n this.modal.getRoot().remove();\n }.bind(this));\n\n this.modal.getRoot().on(ModalEvents.save, this.submitAddNote.bind(this, users));\n\n this.modal.show();\n\n return this.modal;\n }.bind(this));\n };\n\n /**\n * Add a note to this list of users.\n *\n * @method submitAddNote\n * @private\n * @param {int[]} users\n * @return {Promise}\n */\n Participants.prototype.submitAddNote = function(users) {\n var noteText = this.modal.getRoot().find('form textarea').val();\n var publishState = this.modal.getRoot().find('form select').val();\n var notes = [],\n i = 0;\n\n for (i = 0; i < users.length; i++) {\n notes.push({userid: users[i], text: noteText, courseid: this.courseId, publishstate: publishState});\n }\n\n return Ajax.call([{\n methodname: 'core_notes_create_notes',\n args: {notes: notes}\n }])[0].then(function(noteIds) {\n if (noteIds.length == 1) {\n return Str.get_string('addbulknotedonesingle', 'core_notes');\n } else {\n return Str.get_string('addbulknotedone', 'core_notes', noteIds.length);\n }\n }).then(function(msg) {\n Notification.addNotification({\n message: msg,\n type: \"success\"\n });\n return true;\n }).catch(Notification.exception);\n };\n\n /**\n * Show the send message popup.\n *\n * @method showSendMessage\n * @private\n * @param {int[]} users\n * @return {Promise}\n */\n Participants.prototype.showSendMessage = function(users) {\n\n if (users.length == 0) {\n // Nothing to do.\n return $.Deferred().resolve().promise();\n }\n var titlePromise = null;\n if (users.length == 1) {\n titlePromise = Str.get_string('sendbulkmessagesingle', 'core_message');\n } else {\n titlePromise = Str.get_string('sendbulkmessage', 'core_message', users.length);\n }\n\n return $.when(\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n body: Templates.render('core_user/send_bulk_message', {})\n }),\n titlePromise\n ).then(function(modal, title) {\n // Keep a reference to the modal.\n this.modal = modal;\n\n this.modal.setTitle(title);\n this.modal.setSaveButtonText(title);\n\n // We want to focus on the action select when the dialog is closed.\n this.modal.getRoot().on(ModalEvents.hidden, function() {\n $(SELECTORS.BULKACTIONSELECT).focus();\n this.modal.getRoot().remove();\n }.bind(this));\n\n this.modal.getRoot().on(ModalEvents.save, this.submitSendMessage.bind(this, users));\n\n this.modal.show();\n\n return this.modal;\n }.bind(this));\n };\n\n /**\n * Send a message to these users.\n *\n * @method submitSendMessage\n * @private\n * @param {int[]} users\n * @param {Event} e Form submission event.\n * @return {Promise}\n */\n Participants.prototype.submitSendMessage = function(users) {\n\n var messageText = this.modal.getRoot().find('form textarea').val();\n\n var messages = [],\n i = 0;\n\n for (i = 0; i < users.length; i++) {\n messages.push({touserid: users[i], text: messageText});\n }\n\n return Ajax.call([{\n methodname: 'core_message_send_instant_messages',\n args: {messages: messages}\n }])[0].then(function(messageIds) {\n if (messageIds.length == 1) {\n return Str.get_string('sendbulkmessagesentsingle', 'core_message');\n } else {\n return Str.get_string('sendbulkmessagesent', 'core_message', messageIds.length);\n }\n }).then(function(msg) {\n Notification.addNotification({\n message: msg,\n type: \"success\"\n });\n return true;\n }).catch(Notification.exception);\n };\n\n return /** @alias module:core_user/participants */ {\n // Public variables and functions.\n\n /**\n * Initialise the unified user filter.\n *\n * @method init\n * @param {Object} options - List of options.\n * @return {Participants}\n */\n 'init': function(options) {\n return new Participants(options);\n }\n };\n});\n"],"file":"participants.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/participants.js"],"names":["Selectors","bulkActionSelect","bulkUserCheckBoxes","bulkUserSelectedCheckBoxes","checkAllButton","stateHelpIcon","tableForm","uniqueId","init","uniqueid","noteStateNames","root","document","querySelector","getTableFromUniqueId","DynamicTableSelectors","main","fromRegionId","registerEventListeners","addEventListener","CustomEvents","events","accessibleChange","e","action","target","value","tableRoot","checkboxes","querySelectorAll","indexOf","preventDefault","ids","forEach","checkbox","push","getAttribute","replace","bulkAction","dataset","courseId","then","modal","getRoot","on","ModalEvents","hidden","bulkActionSelector","focus","catch","Notification","exception","length","form","submit","resetBulkAction","closest","showAllLink","showalllink","window","location"],"mappings":"wSAyBA,OACA,OACA,OACA,O,sDAGMA,CAAAA,CAAS,CAAG,CACdC,gBAAgB,CAAE,eADJ,CAEdC,kBAAkB,CAAE,oBAFN,CAGdC,0BAA0B,CAAE,4BAHd,CAIdC,cAAc,CAAE,WAJF,CAKdC,aAAa,CAAE,mCALD,CAMdC,SAAS,CAAE,mBAAAC,CAAQ,8CAAkCA,CAAlC,QANL,C,QASE,QAAPC,CAAAA,IAAO,GAGd,IAFFC,CAAAA,CAEE,GAFFA,QAEE,KADFC,cACE,CADFA,CACE,YADe,EACf,GACIC,CAAI,CAAGC,QAAQ,CAACC,aAAT,CAAuBb,CAAS,CAACM,SAAV,CAAoBG,CAApB,CAAvB,CADX,CAEIK,CAAoB,CAAG,SAAAP,CAAQ,QAAII,CAAAA,CAAI,CAACE,aAAL,CAAmBE,UAAsBC,IAAtB,CAA2BC,YAA3B,CAAwCV,CAAxC,CAAnB,CAAJ,CAFnC,CAUIW,CAAsB,CAAG,UAAM,CACjCP,CAAI,CAACE,aAAL,CAAmBb,CAAS,CAACC,gBAA7B,EAA+CkB,gBAA/C,CAAgEC,UAAaC,MAAb,CAAoBC,gBAApF,CAAsG,SAAAC,CAAC,CAAI,IACjGC,CAAAA,CAAM,CAAGD,CAAC,CAACE,MAAF,CAASC,KAD+E,CAEjGC,CAAS,CAAGb,CAAoB,CAACL,CAAD,CAFiE,CAGjGmB,CAAU,CAAGD,CAAS,CAACE,gBAAV,CAA2B7B,CAAS,CAACG,0BAArC,CAHoF,CAKvG,GAA4B,CAAC,CAAzB,GAAAqB,CAAM,CAACM,OAAP,CAAe,GAAf,CAAJ,CAAgC,CAC5BP,CAAC,CAACQ,cAAF,GAEA,GAAMC,CAAAA,CAAG,CAAG,EAAZ,CACAJ,CAAU,CAACK,OAAX,CAAmB,SAAAC,CAAQ,CAAI,CAC3BF,CAAG,CAACG,IAAJ,CAASD,CAAQ,CAACE,YAAT,CAAsB,MAAtB,EAA8BC,OAA9B,CAAsC,MAAtC,CAA8C,EAA9C,CAAT,CACH,CAFD,EAIA,GAAIC,CAAAA,CAAJ,CACA,GAAe,gBAAX,GAAAd,CAAJ,CAAiC,CAC7Bc,CAAU,CAAG,sBAAgBN,CAAhB,CAChB,CAFD,IAEO,IAAe,eAAX,GAAAR,CAAJ,CAAgC,CACnCc,CAAU,CAAG,kBACT3B,CAAI,CAAC4B,OAAL,CAAaC,QADJ,CAETR,CAFS,CAGTtB,CAHS,CAITC,CAAI,CAACE,aAAL,CAAmBb,CAAS,CAACK,aAA7B,CAJS,CAMhB,CAED,GAAIiC,CAAJ,CAAgB,CACZA,CAAU,CACTG,IADD,CACM,SAAAC,CAAK,CAAI,CACXA,CAAK,CAACC,OAAN,GAAgBC,EAAhB,CAAmBC,UAAYC,MAA/B,CAAuC,UAAM,CAEzC,GAAMC,CAAAA,CAAkB,CAAGpC,CAAI,CAACE,aAAL,CAAmBb,CAAS,CAACC,gBAA7B,CAA3B,CACA8C,CAAkB,CAACC,KAAnB,EACH,CAJD,EAMA,MAAON,CAAAA,CACV,CATD,EAUCO,KAVD,CAUOC,UAAaC,SAVpB,CAWH,CACJ,CAjCD,IAiCO,IAAe,EAAX,GAAA3B,CAAM,EAAWI,CAAU,CAACwB,MAAhC,CAAwC,CAC3C7B,CAAC,CAACE,MAAF,CAAS4B,IAAT,CAAcC,MAAd,EACH,CAEDC,CAAe,CAAChC,CAAC,CAACE,MAAH,CAClB,CA3CD,EA6CAd,CAAI,CAACQ,gBAAL,CAAsB,OAAtB,CAA+B,SAAAI,CAAC,CAAI,CAChC,GAAMnB,CAAAA,CAAc,CAAGmB,CAAC,CAACE,MAAF,CAAS+B,OAAT,CAAiBxD,CAAS,CAACI,cAA3B,CAAvB,CACA,GAAIA,CAAJ,CAAoB,CAChB,GAAMqD,CAAAA,CAAW,CAAGrD,CAAc,CAACmC,OAAf,CAAuBmB,WAA3C,CACA,GAAID,CAAJ,CAAiB,CACbE,MAAM,CAACC,QAAP,CAAkBH,CACrB,CACJ,CACJ,CARD,CASH,CAjEC,CAmEIF,CAAe,CAAG,SAAAtD,CAAgB,CAAI,CACxCA,CAAgB,CAACyB,KAAjB,CAAyB,EAC5B,CArEC,CAuEFR,CAAsB,EACzB,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Some UI stuff for participants page.\n * This is also used by the report/participants/index.php because it has the same functionality.\n *\n * @module core_user/participants\n * @package core_user\n * @copyright 2017 Damyon Wiese\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport DynamicTableSelectors from 'core_table/local/dynamic/selectors';\nimport ModalEvents from 'core/modal_events';\nimport Notification from 'core/notification';\nimport CustomEvents from 'core/custom_interaction_events';\nimport {showAddNote, showSendMessage} from 'core_user/local/participants/bulkactions';\n\nconst Selectors = {\n bulkActionSelect: \"#formactionid\",\n bulkUserCheckBoxes: \"input.usercheckbox\",\n bulkUserSelectedCheckBoxes: \"input.usercheckbox:checked\",\n checkAllButton: \"#checkall\",\n stateHelpIcon: '[data-region=\"state-help-icon\"]',\n tableForm: uniqueId => `form[data-table-unique-id=\"${uniqueId}\"]`,\n};\n\nexport const init = ({\n uniqueid,\n noteStateNames = {},\n}) => {\n const root = document.querySelector(Selectors.tableForm(uniqueid));\n const getTableFromUniqueId = uniqueId => root.querySelector(DynamicTableSelectors.main.fromRegionId(uniqueId));\n\n /**\n * Private method.\n *\n * @method registerEventListeners\n * @private\n */\n const registerEventListeners = () => {\n root.querySelector(Selectors.bulkActionSelect).addEventListener(CustomEvents.events.accessibleChange, e => {\n const action = e.target.value;\n const tableRoot = getTableFromUniqueId(uniqueid);\n const checkboxes = tableRoot.querySelectorAll(Selectors.bulkUserSelectedCheckBoxes);\n\n if (action.indexOf('#') !== -1) {\n e.preventDefault();\n\n const ids = [];\n checkboxes.forEach(checkbox => {\n ids.push(checkbox.getAttribute('name').replace('user', ''));\n });\n\n let bulkAction;\n if (action === '#messageselect') {\n bulkAction = showSendMessage(ids);\n } else if (action === '#addgroupnote') {\n bulkAction = showAddNote(\n root.dataset.courseId,\n ids,\n noteStateNames,\n root.querySelector(Selectors.stateHelpIcon)\n );\n }\n\n if (bulkAction) {\n bulkAction\n .then(modal => {\n modal.getRoot().on(ModalEvents.hidden, () => {\n // Focus on the action select when the dialog is closed.\n const bulkActionSelector = root.querySelector(Selectors.bulkActionSelect);\n bulkActionSelector.focus();\n });\n\n return modal;\n })\n .catch(Notification.exception);\n }\n } else if (action !== '' && checkboxes.length) {\n e.target.form.submit();\n }\n\n resetBulkAction(e.target);\n });\n\n root.addEventListener('click', e => {\n const checkAllButton = e.target.closest(Selectors.checkAllButton);\n if (checkAllButton) {\n const showAllLink = checkAllButton.dataset.showalllink;\n if (showAllLink) {\n window.location = showAllLink;\n }\n }\n });\n };\n\n const resetBulkAction = bulkActionSelect => {\n bulkActionSelect.value = '';\n };\n\n registerEventListeners();\n};\n"],"file":"participants.min.js"} \ No newline at end of file diff --git a/user/amd/build/repository.min.js b/user/amd/build/repository.min.js index 5ff57f0f070..fec9ab0154c 100644 --- a/user/amd/build/repository.min.js +++ b/user/amd/build/repository.min.js @@ -1,2 +1,2 @@ -define ("core_user/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.submitUserEnrolmentForm=a.unenrolUser=void 0;a.unenrolUser=function unenrolUser(a){return(0,b.call)([{methodname:"core_enrol_unenrol_user_enrolment",args:{ueid:a}}])[0]};a.submitUserEnrolmentForm=function submitUserEnrolmentForm(a){return(0,b.call)([{methodname:"core_enrol_submit_user_enrolment_form",args:{formdata:a}}])[0]}}); +define ("core_user/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.sendMessagesToUsers=a.createNotesForUsers=a.submitUserEnrolmentForm=a.unenrolUser=void 0;a.unenrolUser=function unenrolUser(a){return(0,b.call)([{methodname:"core_enrol_unenrol_user_enrolment",args:{ueid:a}}])[0]};a.submitUserEnrolmentForm=function submitUserEnrolmentForm(a){return(0,b.call)([{methodname:"core_enrol_submit_user_enrolment_form",args:{formdata:a}}])[0]};a.createNotesForUsers=function createNotesForUsers(a){return(0,b.call)([{methodname:"core_notes_create_notes",args:{notes:a}}])[0]};a.sendMessagesToUsers=function sendMessagesToUsers(a){return(0,b.call)([{methodname:"core_message_send_instant_messages",args:{messages:a}}])[0]}}); //# sourceMappingURL=repository.min.js.map diff --git a/user/amd/build/repository.min.js.map b/user/amd/build/repository.min.js.map index 7d60e609a70..b117500cf86 100644 --- a/user/amd/build/repository.min.js.map +++ b/user/amd/build/repository.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/repository.js"],"names":["unenrolUser","userEnrolmentId","methodname","args","ueid","submitUserEnrolmentForm","formdata"],"mappings":"gMA8B2B,QAAdA,CAAAA,WAAc,CAAAC,CAAe,CAAI,CAC1C,MAAO,WAAU,CAAC,CACdC,UAAU,CAAE,mCADE,CAEdC,IAAI,CAAE,CACFC,IAAI,CAAEH,CADJ,CAFQ,CAAD,CAAV,EAKH,CALG,CAMV,C,2BAQsC,QAA1BI,CAAAA,uBAA0B,CAAAC,CAAQ,CAAI,CAC/C,MAAO,WAAU,CAAC,CACdJ,UAAU,CAAE,uCADE,CAEdC,IAAI,CAAE,CACFG,QAAQ,CAARA,CADE,CAFQ,CAAD,CAAV,EAKH,CALG,CAMV,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Module to handle AJAX interactions.\n *\n * @module core_user/repository\n * @copyright 2020 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {call as fetchMany} from 'core/ajax';\n\n/**\n * Unenrol the user with the specified user enrolmentid ID.\n *\n * @param {Number} userEnrolmentId\n * @return {Promise}\n */\nexport const unenrolUser = userEnrolmentId => {\n return fetchMany([{\n methodname: 'core_enrol_unenrol_user_enrolment',\n args: {\n ueid: userEnrolmentId,\n },\n }])[0];\n};\n\n/**\n * Submit the user enrolment form with the specified form data.\n *\n * @param {String} formdata\n * @return {Promise}\n */\nexport const submitUserEnrolmentForm = formdata => {\n return fetchMany([{\n methodname: 'core_enrol_submit_user_enrolment_form',\n args: {\n formdata,\n },\n }])[0];\n};\n"],"file":"repository.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/repository.js"],"names":["unenrolUser","userEnrolmentId","methodname","args","ueid","submitUserEnrolmentForm","formdata","createNotesForUsers","notes","sendMessagesToUsers","messages"],"mappings":"4OA8B2B,QAAdA,CAAAA,WAAc,CAAAC,CAAe,CAAI,CAC1C,MAAO,WAAU,CAAC,CACdC,UAAU,CAAE,mCADE,CAEdC,IAAI,CAAE,CACFC,IAAI,CAAEH,CADJ,CAFQ,CAAD,CAAV,EAKH,CALG,CAMV,C,2BAQsC,QAA1BI,CAAAA,uBAA0B,CAAAC,CAAQ,CAAI,CAC/C,MAAO,WAAU,CAAC,CACdJ,UAAU,CAAE,uCADE,CAEdC,IAAI,CAAE,CACFG,QAAQ,CAARA,CADE,CAFQ,CAAD,CAAV,EAKH,CALG,CAMV,C,uBAEkC,QAAtBC,CAAAA,mBAAsB,CAAAC,CAAK,CAAI,CACxC,MAAO,WAAU,CAAC,CACdN,UAAU,CAAE,yBADE,CAEdC,IAAI,CAAE,CACFK,KAAK,CAALA,CADE,CAFQ,CAAD,CAAV,EAKH,CALG,CAMV,C,uBAEkC,QAAtBC,CAAAA,mBAAsB,CAAAC,CAAQ,CAAI,CAC3C,MAAO,WAAU,CAAC,CACdR,UAAU,CAAE,oCADE,CAEdC,IAAI,CAAE,CAACO,QAAQ,CAARA,CAAD,CAFQ,CAAD,CAAV,EAGH,CAHG,CAIV,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Module to handle AJAX interactions.\n *\n * @module core_user/repository\n * @copyright 2020 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {call as fetchMany} from 'core/ajax';\n\n/**\n * Unenrol the user with the specified user enrolmentid ID.\n *\n * @param {Number} userEnrolmentId\n * @return {Promise}\n */\nexport const unenrolUser = userEnrolmentId => {\n return fetchMany([{\n methodname: 'core_enrol_unenrol_user_enrolment',\n args: {\n ueid: userEnrolmentId,\n },\n }])[0];\n};\n\n/**\n * Submit the user enrolment form with the specified form data.\n *\n * @param {String} formdata\n * @return {Promise}\n */\nexport const submitUserEnrolmentForm = formdata => {\n return fetchMany([{\n methodname: 'core_enrol_submit_user_enrolment_form',\n args: {\n formdata,\n },\n }])[0];\n};\n\nexport const createNotesForUsers = notes => {\n return fetchMany([{\n methodname: 'core_notes_create_notes',\n args: {\n notes\n }\n }])[0];\n};\n\nexport const sendMessagesToUsers = messages => {\n return fetchMany([{\n methodname: 'core_message_send_instant_messages',\n args: {messages}\n }])[0];\n};\n"],"file":"repository.min.js"} \ No newline at end of file diff --git a/user/amd/src/local/participants/bulkactions.js b/user/amd/src/local/participants/bulkactions.js new file mode 100644 index 00000000000..3872f71ef5a --- /dev/null +++ b/user/amd/src/local/participants/bulkactions.js @@ -0,0 +1,191 @@ +// 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 . + +/** + * Bulk actions for lists of participants. + * + * @module core_user/local/participants/bulkactions + * @package core_user + * @copyright 2020 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import * as Repository from 'core_user/repository'; +import * as Str from 'core/str'; +import ModalEvents from 'core/modal_events'; +import ModalFactory from 'core/modal_factory'; +import Templates from 'core/templates'; +import {add as notifyUser} from 'core/toast'; + +/** + * Show the add note popup + * + * @param {Number} courseid + * @param {Number[]} users + * @param {String[]} noteStateNames + * @param {HTMLElement} stateHelpIcon + * @return {Promise} + */ +export const showAddNote = (courseid, users, noteStateNames, stateHelpIcon) => { + if (!users.length) { + // No users were selected. + return Promise.resolve(); + } + + const states = []; + for (let key in noteStateNames) { + switch (key) { + case 'draft': + states.push({value: 'personal', label: noteStateNames[key]}); + break; + case 'public': + states.push({value: 'course', label: noteStateNames[key], selected: 1}); + break; + case 'site': + states.push({value: key, label: noteStateNames[key]}); + break; + } + } + + const context = { + stateNames: states, + stateHelpIcon: stateHelpIcon.innerHTML, + }; + + let titlePromise = null; + if (users.length === 1) { + titlePromise = Str.get_string('addbulknotesingle', 'core_notes'); + } else { + titlePromise = Str.get_string('addbulknote', 'core_notes', users.length); + } + + return ModalFactory.create({ + type: ModalFactory.types.SAVE_CANCEL, + body: Templates.render('core_user/add_bulk_note', context), + title: titlePromise, + buttons: { + save: titlePromise, + }, + removeOnClose: true, + }) + .then(modal => { + modal.getRoot().on(ModalEvents.save, () => submitAddNote(courseid, users, modal)); + + modal.show(); + + return modal; + }); +}; + +/** + * Add a note to this list of users. + * + * @param {Number} courseid + * @param {Number[]} users + * @param {Modal} modal + * @return {Promise} + */ +const submitAddNote = (courseid, users, modal) => { + const text = modal.getRoot().find('form textarea').val(); + const publishstate = modal.getRoot().find('form select').val(); + + const notes = users.map(userid => { + return { + userid, + text, + courseid, + publishstate, + }; + }); + + return Repository.createNotesForUsers(notes) + .then(noteIds => { + if (noteIds.length === 1) { + return Str.get_string('addbulknotedonesingle', 'core_notes'); + } else { + return Str.get_string('addbulknotedone', 'core_notes', noteIds.length); + } + }) + .then(msg => notifyUser(msg)) + .catch(Notification.exception); +}; + +/** + * Show the send message popup. + * + * @param {Number[]} users + * @return {Promise} + */ +export const showSendMessage = users => { + if (!users.length) { + // Nothing to do. + return Promise.resolve(); + } + + let titlePromise; + if (users.length === 1) { + titlePromise = Str.get_string('sendbulkmessagesingle', 'core_message'); + } else { + titlePromise = Str.get_string('sendbulkmessage', 'core_message', users.length); + } + + return ModalFactory.create({ + type: ModalFactory.types.SAVE_CANCEL, + body: Templates.render('core_user/send_bulk_message', {}), + title: titlePromise, + buttons: { + save: titlePromise, + }, + removeOnClose: true, + }) + .then(modal => { + modal.getRoot().on(ModalEvents.save, () => { + submitSendMessage(modal, users); + }); + + modal.show(); + + return modal; + }); +}; + +/** + * Send a message to these users. + * + * @param {Modal} modal + * @param {Number[]} users + * @return {Promise} + */ +const submitSendMessage = (modal, users) => { + const text = modal.getRoot().find('form textarea').val(); + + const messages = users.map(touserid => { + return { + touserid, + text, + }; + }); + + return Repository.sendMessagesToUsers(messages) + .then(messageIds => { + if (messageIds.length == 1) { + return Str.get_string('sendbulkmessagesentsingle', 'core_message'); + } else { + return Str.get_string('sendbulkmessagesent', 'core_message', messageIds.length); + } + }) + .then(msg => notifyUser(msg)) + .catch(Notification.exception); +}; diff --git a/user/amd/src/participants.js b/user/amd/src/participants.js index d2156d54c8b..eba586aae00 100644 --- a/user/amd/src/participants.js +++ b/user/amd/src/participants.js @@ -22,310 +22,95 @@ * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/templates', 'core/notification', 'core/ajax', - 'core/custom_interaction_events'], - function($, Str, ModalFactory, ModalEvents, Templates, Notification, Ajax, CustomEvents) { - var SELECTORS = { - BULKACTIONSELECT: "#formactionid", - BULKUSERCHECKBOXES: "input.usercheckbox", - BULKUSERNOSCHECKBOXES: "input.usercheckbox[value='0']", - BULKUSERSELECTEDCHECKBOXES: "input.usercheckbox:checked", - BULKACTIONFORM: "#participantsform", - CHECKALLBUTTON: "#checkall", - CHECKALLNOSBUTTON: "#checkallnos" - }; +import DynamicTableSelectors from 'core_table/local/dynamic/selectors'; +import ModalEvents from 'core/modal_events'; +import Notification from 'core/notification'; +import CustomEvents from 'core/custom_interaction_events'; +import {showAddNote, showSendMessage} from 'core_user/local/participants/bulkactions'; + +const Selectors = { + bulkActionSelect: "#formactionid", + bulkUserCheckBoxes: "input.usercheckbox", + bulkUserSelectedCheckBoxes: "input.usercheckbox:checked", + checkAllButton: "#checkall", + stateHelpIcon: '[data-region="state-help-icon"]', + tableForm: uniqueId => `form[data-table-unique-id="${uniqueId}"]`, +}; + +export const init = ({ + uniqueid, + noteStateNames = {}, +}) => { + const root = document.querySelector(Selectors.tableForm(uniqueid)); + const getTableFromUniqueId = uniqueId => root.querySelector(DynamicTableSelectors.main.fromRegionId(uniqueId)); /** - * Constructor + * Private method. * - * @param {Object} options Object containing options. Contextid is required. - * Each call to templates.render gets it's own instance of this class. - */ - var Participants = function(options) { - - this.courseId = options.courseid; - this.noteStateNames = options.noteStateNames; - this.stateHelpIcon = options.stateHelpIcon; - - this.attachEventListeners(); - }; - // Class variables and functions. - - /** - * @var {Modal} modal + * @method registerEventListeners * @private */ - Participants.prototype.modal = null; + const registerEventListeners = () => { + root.querySelector(Selectors.bulkActionSelect).addEventListener(CustomEvents.events.accessibleChange, e => { + const action = e.target.value; + const tableRoot = getTableFromUniqueId(uniqueid); + const checkboxes = tableRoot.querySelectorAll(Selectors.bulkUserSelectedCheckBoxes); - /** - * @var {int} courseId - * @private - */ - Participants.prototype.courseId = -1; - - /** - * @var {Object} noteStateNames - * @private - */ - Participants.prototype.noteStateNames = {}; - - /** - * @var {String} stateHelpIcon - * @private - */ - Participants.prototype.stateHelpIcon = ""; - - /** - * Private method - * - * @method attachEventListeners - * @private - */ - Participants.prototype.attachEventListeners = function() { - CustomEvents.define(SELECTORS.BULKACTIONSELECT, [CustomEvents.events.accessibleChange]); - $(SELECTORS.BULKACTIONSELECT).on(CustomEvents.events.accessibleChange, function(e) { - var action = $(e.target).val(); if (action.indexOf('#') !== -1) { e.preventDefault(); - var ids = []; - $(SELECTORS.BULKUSERSELECTEDCHECKBOXES).each(function(index, ele) { - var name = $(ele).attr('name'); - var id = name.replace('user', ''); - ids.push(id); + const ids = []; + checkboxes.forEach(checkbox => { + ids.push(checkbox.getAttribute('name').replace('user', '')); }); - if (action == '#messageselect') { - this.showSendMessage(ids).fail(Notification.exception); - } else if (action == '#addgroupnote') { - this.showAddNote(ids).fail(Notification.exception); + let bulkAction; + if (action === '#messageselect') { + bulkAction = showSendMessage(ids); + } else if (action === '#addgroupnote') { + bulkAction = showAddNote( + root.dataset.courseId, + ids, + noteStateNames, + root.querySelector(Selectors.stateHelpIcon) + ); } - $(SELECTORS.BULKACTIONSELECT + ' option[value=""]').prop('selected', 'selected'); - } else if (action !== '') { - if ($(SELECTORS.BULKUSERSELECTEDCHECKBOXES).length > 0) { - $(SELECTORS.BULKACTIONFORM).submit(); - } else { - $(SELECTORS.BULKACTIONSELECT + ' option[value=""]').prop('selected', 'selected'); - } - } - }.bind(this)); - $(SELECTORS.CHECKALLBUTTON).on('click', function() { - var showallink = $(this).data('showallink'); - if (showallink) { - window.location = showallink; + if (bulkAction) { + bulkAction + .then(modal => { + modal.getRoot().on(ModalEvents.hidden, () => { + // Focus on the action select when the dialog is closed. + const bulkActionSelector = root.querySelector(Selectors.bulkActionSelect); + bulkActionSelector.focus(); + }); + + return modal; + }) + .catch(Notification.exception); + } + } else if (action !== '' && checkboxes.length) { + e.target.form.submit(); } + + resetBulkAction(e.target); }); - $(SELECTORS.CHECKALLNOSBUTTON).on('click', function() { - $(SELECTORS.BULKUSERNOSCHECKBOXES).prop('checked', true); + root.addEventListener('click', e => { + const checkAllButton = e.target.closest(Selectors.checkAllButton); + if (checkAllButton) { + const showAllLink = checkAllButton.dataset.showalllink; + if (showAllLink) { + window.location = showAllLink; + } + } }); }; - /** - * Show the add note popup - * - * @method showAddNote - * @private - * @param {int[]} users - * @return {Promise} - */ - Participants.prototype.showAddNote = function(users) { - - if (users.length == 0) { - // Nothing to do. - return $.Deferred().resolve().promise(); - } - - var states = []; - for (var key in this.noteStateNames) { - switch (key) { - case 'draft': - states.push({value: 'personal', label: this.noteStateNames[key]}); - break; - case 'public': - states.push({value: 'course', label: this.noteStateNames[key], selected: 1}); - break; - case 'site': - states.push({value: key, label: this.noteStateNames[key]}); - break; - } - } - - var context = {stateNames: states, stateHelpIcon: this.stateHelpIcon}; - var titlePromise = null; - if (users.length == 1) { - titlePromise = Str.get_string('addbulknotesingle', 'core_notes'); - } else { - titlePromise = Str.get_string('addbulknote', 'core_notes', users.length); - } - - return $.when( - ModalFactory.create({ - type: ModalFactory.types.SAVE_CANCEL, - body: Templates.render('core_user/add_bulk_note', context) - }), - titlePromise - ).then(function(modal, title) { - // Keep a reference to the modal. - this.modal = modal; - this.modal.setTitle(title); - this.modal.setSaveButtonText(title); - - // We want to focus on the action select when the dialog is closed. - this.modal.getRoot().on(ModalEvents.hidden, function() { - var notification = $('#user-notifications [role=alert]'); - if (notification.length) { - notification.focus(); - } else { - $(SELECTORS.BULKACTIONSELECT).focus(); - } - this.modal.getRoot().remove(); - }.bind(this)); - - this.modal.getRoot().on(ModalEvents.save, this.submitAddNote.bind(this, users)); - - this.modal.show(); - - return this.modal; - }.bind(this)); + const resetBulkAction = bulkActionSelect => { + bulkActionSelect.value = ''; }; - /** - * Add a note to this list of users. - * - * @method submitAddNote - * @private - * @param {int[]} users - * @return {Promise} - */ - Participants.prototype.submitAddNote = function(users) { - var noteText = this.modal.getRoot().find('form textarea').val(); - var publishState = this.modal.getRoot().find('form select').val(); - var notes = [], - i = 0; - - for (i = 0; i < users.length; i++) { - notes.push({userid: users[i], text: noteText, courseid: this.courseId, publishstate: publishState}); - } - - return Ajax.call([{ - methodname: 'core_notes_create_notes', - args: {notes: notes} - }])[0].then(function(noteIds) { - if (noteIds.length == 1) { - return Str.get_string('addbulknotedonesingle', 'core_notes'); - } else { - return Str.get_string('addbulknotedone', 'core_notes', noteIds.length); - } - }).then(function(msg) { - Notification.addNotification({ - message: msg, - type: "success" - }); - return true; - }).catch(Notification.exception); - }; - - /** - * Show the send message popup. - * - * @method showSendMessage - * @private - * @param {int[]} users - * @return {Promise} - */ - Participants.prototype.showSendMessage = function(users) { - - if (users.length == 0) { - // Nothing to do. - return $.Deferred().resolve().promise(); - } - var titlePromise = null; - if (users.length == 1) { - titlePromise = Str.get_string('sendbulkmessagesingle', 'core_message'); - } else { - titlePromise = Str.get_string('sendbulkmessage', 'core_message', users.length); - } - - return $.when( - ModalFactory.create({ - type: ModalFactory.types.SAVE_CANCEL, - body: Templates.render('core_user/send_bulk_message', {}) - }), - titlePromise - ).then(function(modal, title) { - // Keep a reference to the modal. - this.modal = modal; - - this.modal.setTitle(title); - this.modal.setSaveButtonText(title); - - // We want to focus on the action select when the dialog is closed. - this.modal.getRoot().on(ModalEvents.hidden, function() { - $(SELECTORS.BULKACTIONSELECT).focus(); - this.modal.getRoot().remove(); - }.bind(this)); - - this.modal.getRoot().on(ModalEvents.save, this.submitSendMessage.bind(this, users)); - - this.modal.show(); - - return this.modal; - }.bind(this)); - }; - - /** - * Send a message to these users. - * - * @method submitSendMessage - * @private - * @param {int[]} users - * @param {Event} e Form submission event. - * @return {Promise} - */ - Participants.prototype.submitSendMessage = function(users) { - - var messageText = this.modal.getRoot().find('form textarea').val(); - - var messages = [], - i = 0; - - for (i = 0; i < users.length; i++) { - messages.push({touserid: users[i], text: messageText}); - } - - return Ajax.call([{ - methodname: 'core_message_send_instant_messages', - args: {messages: messages} - }])[0].then(function(messageIds) { - if (messageIds.length == 1) { - return Str.get_string('sendbulkmessagesentsingle', 'core_message'); - } else { - return Str.get_string('sendbulkmessagesent', 'core_message', messageIds.length); - } - }).then(function(msg) { - Notification.addNotification({ - message: msg, - type: "success" - }); - return true; - }).catch(Notification.exception); - }; - - return /** @alias module:core_user/participants */ { - // Public variables and functions. - - /** - * Initialise the unified user filter. - * - * @method init - * @param {Object} options - List of options. - * @return {Participants} - */ - 'init': function(options) { - return new Participants(options); - } - }; -}); + registerEventListeners(); +}; diff --git a/user/amd/src/repository.js b/user/amd/src/repository.js index 7be9378875f..c719bc12046 100644 --- a/user/amd/src/repository.js +++ b/user/amd/src/repository.js @@ -51,3 +51,19 @@ export const submitUserEnrolmentForm = formdata => { }, }])[0]; }; + +export const createNotesForUsers = notes => { + return fetchMany([{ + methodname: 'core_notes_create_notes', + args: { + notes + } + }])[0]; +}; + +export const sendMessagesToUsers = messages => { + return fetchMany([{ + methodname: 'core_message_send_instant_messages', + args: {messages} + }])[0]; +}; diff --git a/user/index.php b/user/index.php index 92f81e2bfdb..4aa5fcb647f 100644 --- a/user/index.php +++ b/user/index.php @@ -289,7 +289,13 @@ ob_end_clean(); echo html_writer::tag('p', get_string('participantscount', 'moodle', $participanttable->totalrows)); if ($bulkoperations) { - echo ''; + echo html_writer::start_tag('form', [ + 'action' => 'action_redir.php', + 'method' => 'post', + 'id' => 'participantsform', + 'data-course-id' => $course->id, + 'data-table-unique-id' => $participanttable->uniqueid, + ]); echo ''; echo ''; echo ''; @@ -392,13 +398,14 @@ if ($bulkoperations) { echo html_writer::tag('div', $label . $select); echo ''; + echo '' . $OUTPUT->help_icon('publishstate', 'notes') . ''; echo ''; echo ''; - $options = new stdClass(); - $options->courseid = $course->id; - $options->noteStateNames = note_get_state_names(); - $options->stateHelpIcon = $OUTPUT->help_icon('publishstate', 'notes'); + $options = (object) [ + 'uniqueid' => $participanttable->uniqueid, + 'noteStateNames' => note_get_state_names(), + ]; $PAGE->requires->js_call_amd('core_user/participants', 'init', [$options]); }