MDL-60590 enrol_manual: Fix for race condition in button calculation
[moodle.git] / enrol / manual / amd / src / quickenrolment.js
1 // This file is part of Moodle - http://moodle.org/
2 //
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16 /**
17  * Quick enrolment AMD module.
18  *
19  * @module     enrol_manual/quickenrolment
20  * @copyright  2016 Damyon Wiese <damyon@moodle.com>
21  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22  */
23 define(['core/templates',
24          'jquery',
25          'core/str',
26          'core/config',
27          'core/notification',
28          'core/modal_factory',
29          'core/modal_events',
30          'core/fragment',
31        ],
32        function(Template, $, Str, Config, Notification, ModalFactory, ModalEvents, Fragment) {
34     /** @type {Object} The list of selectors for the quick enrolment modal. */
35     var SELECTORS = {
36         COHORTSELECT: "#id_cohortlist",
37         TRIGGERBUTTONS: ".enrolusersbutton.enrol_manual_plugin [type='submit']",
38         UNWANTEDHIDDENFIELDS: ":input[value='_qf__force_multiselect_submission']"
39     };
41     /**
42      * Constructor
43      *
44      * @param {Object} options Object containing options. The only valid option at this time is contextid.
45      * Each call to templates.render gets it's own instance of this class.
46      */
47     var QuickEnrolment = function(options) {
48         this.contextid = options.contextid;
50         this.initModal();
51     };
52     // Class variables and functions.
54     /** @var {number} courseid - */
55     QuickEnrolment.prototype.courseid = 0;
57     /** @var {Modal} modal */
58     QuickEnrolment.prototype.modal = null;
60     /**
61      * Private method
62      *
63      * @method initModal
64      * @private
65      */
66     QuickEnrolment.prototype.initModal = function() {
67         var triggerButtons = $(SELECTORS.TRIGGERBUTTONS);
69         $.when(
70             Str.get_strings([
71                 {key: 'enroluserscohorts', component: 'enrol_manual'},
72                 {key: 'enrolusers', component: 'enrol_manual'},
73             ]),
74             ModalFactory.create({
75                 type: ModalFactory.types.SAVE_CANCEL,
76                 large: true,
77             }, triggerButtons)
78         )
79         .then(function(strings, modal) {
80             this.modal = modal;
82             modal.setTitle(strings[1]);
83             modal.setSaveButtonText(strings[1]);
85             modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));
86             modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));
88             // We want the reset the form every time it is opened.
89             modal.getRoot().on(ModalEvents.hidden, function() {
90                 modal.setBody('');
91             });
93             modal.getRoot().on(ModalEvents.shown, function() {
94                 var bodyPromise = this.getBody();
95                 bodyPromise.then(function(html) {
96                     var stringIndex = $(html).find(SELECTORS.COHORTSELECT).length ? 0 : 1;
97                     modal.setSaveButtonText(strings[stringIndex]);
99                     return;
100                 })
101                 .fail(Notification.exception);
103                 modal.setBody(bodyPromise);
104             }.bind(this));
106             return;
107         }.bind(this))
108         .fail(Notification.exception);
109     };
111     /**
112      * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.
113      *
114      * @method submitForm
115      * @param {Event} e Form submission event.
116      * @private
117      */
118     QuickEnrolment.prototype.submitForm = function(e) {
119         e.preventDefault();
120         this.modal.getRoot().find('form').submit();
121     };
123     /**
124      * Private method
125      *
126      * @method submitForm
127      * @private
128      * @param {Event} e Form submission event.
129      */
130     QuickEnrolment.prototype.submitFormAjax = function(e) {
131         // We don't want to do a real form submission.
132         e.preventDefault();
134         var form = this.modal.getRoot().find('form');
136         // Before send the data through AJAX, we need to parse and remove some unwanted hidden fields.
137         // This hidden fields are added automatically by mforms and when it reaches the AJAX we get an error.
138         var hidden = form.find(SELECTORS.UNWANTEDHIDDENFIELDS);
139         hidden.each(function() {
140             this.remove();
141         });
143         var formData = form.serialize();
145         this.modal.hide();
147         var settings = {
148             type: 'GET',
149             processData: false,
150             contentType: "application/json"
151         };
153         var script = Config.wwwroot + '/enrol/manual/ajax.php?' + formData;
154         $.ajax(script, settings)
155             .then(function(response) {
157                 if (response.error) {
158                     Notification.addNotification({
159                         message: response.error,
160                         type: "error"
161                     });
162                 } else {
163                     // Reload the page, don't show changed data warnings.
164                     if (typeof window.M.core_formchangechecker !== "undefined") {
165                         window.M.core_formchangechecker.reset_form_dirty_state();
166                     }
167                     window.location.reload();
168                 }
169                 return;
170             })
171             .fail(Notification.exception);
172     };
174     /**
175      * Private method
176      *
177      * @method getBody
178      * @private
179      * @return {Promise}
180      */
181     QuickEnrolment.prototype.getBody = function() {
182         return Fragment.loadFragment('enrol_manual', 'enrol_users_form', this.contextid, {}).fail(Notification.exception);
183     };
185     /**
186      * Private method
187      *
188      * @method getFooter
189      * @private
190      * @return {Promise}
191      */
192     QuickEnrolment.prototype.getFooter = function() {
193         return Template.render('enrol_manual/enrol_modal_footer', {});
194     };
196     return /** @alias module:enrol_manual/quickenrolment */ {
197         // Public variables and functions.
198         /**
199          * Every call to init creates a new instance of the class with it's own event listeners etc.
200          *
201          * @method init
202          * @public
203          * @param {object} config - config variables for the module.
204          */
205         init: function(config) {
206             (new QuickEnrolment(config));
207         }
208     };
209 });