MDL-61055 calendar: guest user cannot create events
[moodle.git] / calendar / amd / src / calendar.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  * This module is the highest level module for the calendar. It is
18  * responsible for initialising all of the components required for
19  * the calendar to run. It also coordinates the interaction between
20  * components by listening for and responding to different events
21  * triggered within the calendar UI.
22  *
23  * @module     core_calendar/calendar
24  * @package    core_calendar
25  * @copyright  2017 Simey Lameze <simey@moodle.com>
26  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27  */
28 define([
29             'jquery',
30             'core/ajax',
31             'core/str',
32             'core/templates',
33             'core/notification',
34             'core/custom_interaction_events',
35             'core/modal_events',
36             'core/modal_factory',
37             'core_calendar/modal_event_form',
38             'core_calendar/summary_modal',
39             'core_calendar/repository',
40             'core_calendar/events',
41             'core_calendar/view_manager',
42             'core_calendar/crud',
43             'core_calendar/selectors',
44         ],
45         function(
46             $,
47             Ajax,
48             Str,
49             Templates,
50             Notification,
51             CustomEvents,
52             ModalEvents,
53             ModalFactory,
54             ModalEventForm,
55             SummaryModal,
56             CalendarRepository,
57             CalendarEvents,
58             CalendarViewManager,
59             CalendarCrud,
60             CalendarSelectors
61         ) {
63     var SELECTORS = {
64         ROOT: "[data-region='calendar']",
65         DAY: "[data-region='day']",
66         NEW_EVENT_BUTTON: "[data-action='new-event-button']",
67         DAY_CONTENT: "[data-region='day-content']",
68         LOADING_ICON: '.loading-icon',
69         VIEW_DAY_LINK: "[data-action='view-day-link']",
70         CALENDAR_MONTH_WRAPPER: ".calendarwrapper",
71         TODAY: '.today',
72     };
74     /**
75      * Handler for the drag and drop move event. Provides a loading indicator
76      * while the request is sent to the server to update the event start date.
77      *
78      * Triggers a eventMoved calendar javascript event if the event was successfully
79      * updated.
80      *
81      * @param {event} e The calendar move event
82      * @param {int} eventId The event id being moved
83      * @param {object|null} originElement The jQuery element for where the event is moving from
84      * @param {object} destinationElement The jQuery element for where the event is moving to
85      */
86     var handleMoveEvent = function(e, eventId, originElement, destinationElement) {
87         var originTimestamp = null;
88         var destinationTimestamp = destinationElement.attr('data-day-timestamp');
90         if (originElement) {
91             originTimestamp = originElement.attr('data-day-timestamp');
92         }
94         // If the event has actually changed day.
95         if (!originElement || originTimestamp != destinationTimestamp) {
96             Templates.render('core/loading', {})
97                 .then(function(html, js) {
98                     // First we show some loading icons in each of the days being affected.
99                     destinationElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');
100                     Templates.appendNodeContents(destinationElement, html, js);
102                     if (originElement) {
103                         originElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');
104                         Templates.appendNodeContents(originElement, html, js);
105                     }
106                     return;
107                 })
108                 .then(function() {
109                     // Send a request to the server to make the change.
110                     return CalendarRepository.updateEventStartDay(eventId, destinationTimestamp);
111                 })
112                 .then(function() {
113                     // If the update was successful then broadcast an event letting the calendar
114                     // know that an event has been moved.
115                     $('body').trigger(CalendarEvents.eventMoved, [eventId, originElement, destinationElement]);
116                     return;
117                 })
118                 .always(function() {
119                     // Always remove the loading icons regardless of whether the update
120                     // request was successful or not.
121                     var destinationLoadingElement = destinationElement.find(SELECTORS.LOADING_ICON);
122                     destinationElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');
123                     Templates.replaceNode(destinationLoadingElement, '', '');
125                     if (originElement) {
126                         var originLoadingElement = originElement.find(SELECTORS.LOADING_ICON);
127                         originElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');
128                         Templates.replaceNode(originLoadingElement, '', '');
129                     }
130                     return;
131                 })
132                 .fail(Notification.exception);
133         }
134     };
136     /**
137      * Listen to and handle any calendar events fired by the calendar UI.
138      *
139      * @method registerCalendarEventListeners
140      * @param {object} root The calendar root element
141      * @param {object} eventFormModalPromise A promise reolved with the event form modal
142      */
143     var registerCalendarEventListeners = function(root, eventFormModalPromise) {
144         var body = $('body');
146         body.on(CalendarEvents.created, function() {
147             CalendarViewManager.reloadCurrentMonth(root);
148         });
149         body.on(CalendarEvents.deleted, function() {
150             CalendarViewManager.reloadCurrentMonth(root);
151         });
152         body.on(CalendarEvents.updated, function() {
153             CalendarViewManager.reloadCurrentMonth(root);
154         });
155         body.on(CalendarEvents.editActionEvent, function(e, url) {
156             // Action events needs to be edit directly on the course module.
157             window.location.assign(url);
158         });
159         // Handle the event fired by the drag and drop code.
160         body.on(CalendarEvents.moveEvent, handleMoveEvent);
161         // When an event is successfully moved we should updated the UI.
162         body.on(CalendarEvents.eventMoved, function() {
163             CalendarViewManager.reloadCurrentMonth(root);
164         });
166         CalendarCrud.registerEditListeners(root, eventFormModalPromise);
167     };
169     /**
170      * Register event listeners for the module.
171      *
172      * @param {object} root The calendar root element
173      */
174     var registerEventListeners = function(root) {
175         root.on('change', CalendarSelectors.elements.courseSelector, function() {
176             var selectElement = $(this);
177             var courseId = selectElement.val();
178             CalendarViewManager.reloadCurrentMonth(root, courseId, null)
179                 .then(function() {
180                     // We need to get the selector again because the content has changed.
181                     return root.find(CalendarSelectors.elements.courseSelector).val(courseId);
182                 })
183                 .fail(Notification.exception);
184         });
186         var eventFormPromise = CalendarCrud.registerEventFormModal(root),
187             contextId = $(SELECTORS.CALENDAR_MONTH_WRAPPER).data('context-id');
188         registerCalendarEventListeners(root, eventFormPromise);
190         if (contextId) {
191             // Bind click events to calendar days.
192             root.on('click', SELECTORS.DAY, function (e) {
194                 var target = $(e.target);
196                 if (!target.is(SELECTORS.VIEW_DAY_LINK)) {
197                     var startTime = $(this).attr('data-new-event-timestamp');
198                     eventFormPromise.then(function (modal) {
199                         var wrapper = target.closest(CalendarSelectors.wrapper);
200                         modal.setCourseId(wrapper.data('courseid'));
202                         var categoryId = wrapper.data('categoryid');
203                         if (typeof categoryId !== 'undefined') {
204                             modal.setCategoryId(categoryId);
205                         }
207                         modal.setContextId(wrapper.data('contextId'));
208                         modal.setStartTime(startTime);
209                         modal.show();
210                         return;
211                     })
212                     .fail(Notification.exception);
214                     e.preventDefault();
215                 }
216             });
217         }
218     };
220     return {
221         init: function(root) {
222             root = $(root);
223             CalendarViewManager.init(root);
224             registerEventListeners(root);
225         }
226     };
227 });