MDL-59934 calendar: remove more button from event form modal
[moodle.git] / calendar / amd / src / modal_event_form.js
CommitLineData
aa091225
RW
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/>.
15
16/**
17 * Contain the logic for the quick add or update event modal.
18 *
19 * @module calendar/modal_quick_add_event
20 * @class modal_quick_add_event
21 * @package core
22 * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25define([
26 'jquery',
27 'core/event',
28 'core/str',
29 'core/notification',
30 'core/templates',
31 'core/custom_interaction_events',
32 'core/modal',
33 'core/modal_registry',
34 'core/fragment',
35 'core_calendar/events',
02e091b1 36 'core_calendar/repository'
aa091225
RW
37 ],
38 function(
39 $,
40 Event,
41 Str,
42 Notification,
43 Templates,
44 CustomEvents,
45 Modal,
46 ModalRegistry,
47 Fragment,
48 CalendarEvents,
02e091b1 49 Repository
aa091225
RW
50 ) {
51
52 var registered = false;
53 var SELECTORS = {
aa091225
RW
54 SAVE_BUTTON: '[data-action="save"]',
55 LOADING_ICON_CONTAINER: '[data-region="loading-icon-container"]',
56 };
57
58 /**
59 * Constructor for the Modal.
60 *
61 * @param {object} root The root jQuery element for the modal
62 */
63 var ModalEventForm = function(root) {
64 Modal.call(this, root);
65 this.eventId = null;
f6e8cc83 66 this.startTime = null;
29158c8b 67 this.courseId = null;
aa091225
RW
68 this.reloadingBody = false;
69 this.reloadingTitle = false;
70 this.saveButton = this.getFooter().find(SELECTORS.SAVE_BUTTON);
aa091225
RW
71 };
72
73 ModalEventForm.TYPE = 'core_calendar-modal_event_form';
74 ModalEventForm.prototype = Object.create(Modal.prototype);
75 ModalEventForm.prototype.constructor = ModalEventForm;
dd04df41 76
29158c8b
SL
77 /**
78 * Set the course id to the given value.
79 *
80 * @method setCourseId
81 * @param {int} id The event id
82 */
83 ModalEventForm.prototype.setCourseId = function(id) {
84 this.courseId = id;
85 };
86
87 /**
88 * Retrieve the current course id, if any.
89 *
90 * @method getCourseId
91 * @return {int|null} The event id
92 */
93 ModalEventForm.prototype.getCourseId = function() {
94 return this.courseId;
95 };
96
97 /**
98 * Check if the modal has an course id.
99 *
100 * @method hasCourseId
101 * @return {bool}
102 */
103 ModalEventForm.prototype.hasCourseId = function() {
104 return this.courseId !== null;
105 };
aa091225
RW
106
107 /**
108 * Set the event id to the given value.
109 *
110 * @method setEventId
111 * @param {int} id The event id
112 */
113 ModalEventForm.prototype.setEventId = function(id) {
114 this.eventId = id;
115 };
116
117 /**
118 * Retrieve the current event id, if any.
119 *
120 * @method getEventId
121 * @return {int|null} The event id
122 */
123 ModalEventForm.prototype.getEventId = function() {
124 return this.eventId;
125 };
126
127 /**
128 * Check if the modal has an event id.
129 *
130 * @method hasEventId
131 * @return {bool}
132 */
133 ModalEventForm.prototype.hasEventId = function() {
134 return this.eventId !== null;
135 };
136
f6e8cc83
RW
137 /**
138 * Set the start time to the given value.
139 *
140 * @method setStartTime
141 * @param {int} time The start time
142 */
143 ModalEventForm.prototype.setStartTime = function(time) {
144 this.startTime = time;
145 };
146
147 /**
148 * Retrieve the current start time, if any.
149 *
150 * @method getStartTime
151 * @return {int|null} The start time
152 */
153 ModalEventForm.prototype.getStartTime = function() {
154 return this.startTime;
155 };
156
157 /**
158 * Check if the modal has start time.
159 *
160 * @method hasStartTime
161 * @return {bool}
162 */
163 ModalEventForm.prototype.hasStartTime = function() {
164 return this.startTime !== null;
165 };
166
aa091225
RW
167 /**
168 * Get the form element from the modal.
169 *
170 * @method getForm
171 * @return {object}
172 */
173 ModalEventForm.prototype.getForm = function() {
174 return this.getBody().find('form');
175 };
176
177 /**
178 * Disable the buttons in the footer.
179 *
180 * @method disableButtons
181 */
182 ModalEventForm.prototype.disableButtons = function() {
183 this.saveButton.prop('disabled', true);
aa091225
RW
184 };
185
186 /**
187 * Enable the buttons in the footer.
188 *
189 * @method enableButtons
190 */
191 ModalEventForm.prototype.enableButtons = function() {
192 this.saveButton.prop('disabled', false);
aa091225
RW
193 };
194
195 /**
196 * Reload the title for the modal to the appropriate value
197 * depending on whether we are creating a new event or
198 * editing an existing event.
199 *
200 * @method reloadTitleContent
201 * @return {object} A promise resolved with the new title text
202 */
203 ModalEventForm.prototype.reloadTitleContent = function() {
204 if (this.reloadingTitle) {
205 return this.titlePromise;
206 }
207
208 this.reloadingTitle = true;
209
210 if (this.hasEventId()) {
211 this.titlePromise = Str.get_string('editevent', 'calendar');
212 } else {
213 this.titlePromise = Str.get_string('newevent', 'calendar');
214 }
215
216 this.titlePromise.then(function(string) {
217 this.setTitle(string);
218 return string;
219 }.bind(this))
220 .always(function() {
221 this.reloadingTitle = false;
222 return;
223 }.bind(this));
224
225 return this.titlePromise;
226 };
227
228 /**
229 * Send a request to the server to get the event_form in a fragment
230 * and render the result in the body of the modal.
231 *
232 * If serialised form data is provided then it will be sent in the
233 * request to the server to have the form rendered with the data. This
234 * is used when the form had a server side error and we need the server
235 * to re-render it for us to display the error to the user.
236 *
237 * @method reloadBodyContent
238 * @param {string} formData The serialised form data
aa091225
RW
239 * @return {object} A promise resolved with the fragment html and js from
240 */
02e091b1 241 ModalEventForm.prototype.reloadBodyContent = function(formData) {
aa091225
RW
242 if (this.reloadingBody) {
243 return this.bodyPromise;
244 }
245
246 this.reloadingBody = true;
247 this.disableButtons();
248
249 var contextId = this.saveButton.attr('data-context-id');
250 var args = {};
251
252 if (this.hasEventId()) {
253 args.eventid = this.getEventId();
254 }
255
f6e8cc83
RW
256 if (this.hasStartTime()) {
257 args.starttime = this.getStartTime();
258 }
259
dd04df41 260 if (this.hasCourseId()) {
29158c8b
SL
261 args.courseid = this.getCourseId();
262 }
263
aa091225
RW
264 if (typeof formData !== 'undefined') {
265 args.formdata = formData;
266 }
267
aa091225
RW
268 this.bodyPromise = Fragment.loadFragment('calendar', 'event_form', contextId, args);
269
270 this.setBody(this.bodyPromise);
271
272 this.bodyPromise.then(function() {
273 this.enableButtons();
274 return;
275 }.bind(this))
276 .catch(Notification.exception)
277 .always(function() {
278 this.reloadingBody = false;
279 return;
280 }.bind(this));
281
282 return this.bodyPromise;
283 };
284
285 /**
286 * Reload both the title and body content.
287 *
288 * @method reloadAllContent
289 * @return {object} promise
290 */
291 ModalEventForm.prototype.reloadAllContent = function() {
292 return $.when(this.reloadTitleContent(), this.reloadBodyContent());
293 };
294
295 /**
296 * Kick off a reload the modal content before showing it. This
297 * is to allow us to re-use the same modal for creating and
298 * editing different events within the page.
299 *
300 * We do the reload when showing the modal rather than hiding it
301 * to save a request to the server if the user closes the modal
302 * and never re-opens it.
303 *
304 * @method show
305 */
306 ModalEventForm.prototype.show = function() {
307 this.reloadAllContent();
308 Modal.prototype.show.call(this);
309 };
310
311 /**
312 * Clear the event id from the modal when it's closed so
313 * that it is loaded fresh next time it's displayed.
314 *
315 * The event id will be set by the calling code if it wants
316 * to edit a specific event.
317 *
318 * @method hide
319 */
320 ModalEventForm.prototype.hide = function() {
321 Modal.prototype.hide.call(this);
322 this.setEventId(null);
f6e8cc83 323 this.setStartTime(null);
aa091225
RW
324 };
325
326 /**
327 * Get the serialised form data.
328 *
329 * @method getFormData
330 * @return {string} serialised form data
331 */
332 ModalEventForm.prototype.getFormData = function() {
333 return this.getForm().serialize();
334 };
335
336 /**
337 * Send the form data to the server to create or update
338 * an event.
339 *
340 * If there is a server side validation error then we re-request the
341 * rendered form (with the data) from the server in order to get the
342 * server side errors to display.
343 *
344 * On success the modal is hidden and the page is reloaded so that the
345 * new event will display.
346 *
347 * @method save
348 * @return {object} A promise
349 */
350 ModalEventForm.prototype.save = function() {
351 var loadingContainer = this.saveButton.find(SELECTORS.LOADING_ICON_CONTAINER);
352
353 loadingContainer.removeClass('hidden');
354 this.disableButtons();
355
356 var formData = this.getFormData();
357 // Send the form data to the server for processing.
358 return Repository.submitCreateUpdateForm(formData)
359 .then(function(response) {
360 if (response.validationerror) {
361 // If there was a server side validation error then
362 // we need to re-request the rendered form from the server
363 // in order to display the error for the user.
02e091b1 364 return this.reloadBodyContent(formData);
aa091225
RW
365 } else {
366 // No problemo! Our work here is done.
367 this.hide();
368
369 // Trigger the appropriate calendar event so that the view can
370 // be updated.
371 if (this.hasEventId()) {
372 $('body').trigger(CalendarEvents.updated, [response.event]);
373 } else {
374 $('body').trigger(CalendarEvents.created, [response.event]);
375 }
376 }
d6942fb5
RW
377
378 return;
aa091225
RW
379 }.bind(this))
380 .always(function() {
381 // Regardless of success or error we should always stop
382 // the loading icon and re-enable the buttons.
383 loadingContainer.addClass('hidden');
384 this.enableButtons();
385 }.bind(this))
386 .catch(Notification.exception);
387 };
388
389 /**
390 * Set up all of the event handling for the modal.
391 *
392 * @method registerEventListeners
393 */
394 ModalEventForm.prototype.registerEventListeners = function() {
395 // Apply parent event listeners.
396 Modal.prototype.registerEventListeners.call(this);
397
398 // When the user clicks the save button we trigger the form submission. We need to
399 // trigger an actual submission because there is some JS code in the form that is
400 // listening for this event and doing some stuff (e.g. saving draft areas etc).
401 this.getModal().on(CustomEvents.events.activate, SELECTORS.SAVE_BUTTON, function(e, data) {
402 this.getForm().submit();
403 data.originalEvent.preventDefault();
404 e.stopPropagation();
405 }.bind(this));
406
407 // Catch the submit event before it is actually processed by the browser and
408 // prevent the submission. We'll take it from here.
409 this.getModal().on('submit', function(e) {
410 this.save();
411
412 // Stop the form from actually submitting and prevent it's
413 // propagation because we have already handled the event.
414 e.preventDefault();
415 e.stopPropagation();
416 }.bind(this));
aa091225
RW
417 };
418
419 // Automatically register with the modal registry the first time this module is imported so that you can create modals
420 // of this type using the modal factory.
421 if (!registered) {
422 ModalRegistry.register(ModalEventForm.TYPE, ModalEventForm, 'calendar/modal_event_form');
423 registered = true;
424 }
425
426 return ModalEventForm;
427});