Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 * 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
 * @copyright  2017 Simey Lameze <simey@moodle.com>
25
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26
 */
27
define([
28
    'jquery',
29
    'core/templates',
30
    'core/notification',
31
    'core_calendar/repository',
32
    'core_calendar/events',
33
    'core_calendar/view_manager',
34
    'core_calendar/crud',
35
    'core_calendar/selectors',
36
    'core/url',
37
    'core/str',
38
],
39
function(
40
    $,
41
    Templates,
42
    Notification,
43
    CalendarRepository,
44
    CalendarEvents,
45
    CalendarViewManager,
46
    CalendarCrud,
47
    CalendarSelectors,
48
    Url,
49
    Str,
50
) {
51
 
52
    var SELECTORS = {
53
        ROOT: "[data-region='calendar']",
54
        DAY: "[data-region='day']",
55
        NEW_EVENT_BUTTON: "[data-action='new-event-button']",
56
        DAY_CONTENT: "[data-region='day-content']",
57
        LOADING_ICON: '.loading-icon',
58
        VIEW_DAY_LINK: "[data-action='view-day-link']",
59
        CALENDAR_MONTH_WRAPPER: ".calendarwrapper",
60
        TODAY: '.today',
61
        DAY_NUMBER_CIRCLE: '.day-number-circle',
62
        DAY_NUMBER: '.day-number',
63
        SCREEN_READER_ANNOUNCEMENTS: '.calendar-announcements',
64
        CURRENT_MONTH: '.calendar-controls .current'
65
    };
66
 
67
    /**
68
     * Handler for the drag and drop move event. Provides a loading indicator
69
     * while the request is sent to the server to update the event start date.
70
     *
71
     * Triggers a eventMoved calendar javascript event if the event was successfully
72
     * updated.
73
     *
74
     * @param {event} e The calendar move event
75
     * @param {int} eventId The event id being moved
76
     * @param {object|null} originElement The jQuery element for where the event is moving from
77
     * @param {object} destinationElement The jQuery element for where the event is moving to
78
     */
79
    var handleMoveEvent = function(e, eventId, originElement, destinationElement) {
80
        var originTimestamp = null;
81
        var destinationTimestamp = destinationElement.attr('data-day-timestamp');
82
 
83
        if (originElement) {
84
            originTimestamp = originElement.attr('data-day-timestamp');
85
        }
86
 
87
        // If the event has actually changed day.
88
        if (!originElement || originTimestamp != destinationTimestamp) {
89
            Templates.render('core/loading', {})
90
                .then(function(html, js) {
91
                    // First we show some loading icons in each of the days being affected.
92
                    destinationElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');
93
                    Templates.appendNodeContents(destinationElement, html, js);
94
 
95
                    if (originElement) {
96
                        originElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');
97
                        Templates.appendNodeContents(originElement, html, js);
98
                    }
99
                    return;
100
                })
101
                .then(function() {
102
                    // Send a request to the server to make the change.
103
                    return CalendarRepository.updateEventStartDay(eventId, destinationTimestamp);
104
                })
105
                .then(function() {
106
                    // If the update was successful then broadcast an event letting the calendar
107
                    // know that an event has been moved.
108
                    $('body').trigger(CalendarEvents.eventMoved, [eventId, originElement, destinationElement]);
109
                    return;
110
                })
111
                .always(function() {
112
                    // Always remove the loading icons regardless of whether the update
113
                    // request was successful or not.
114
                    var destinationLoadingElement = destinationElement.find(SELECTORS.LOADING_ICON);
115
                    destinationElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');
116
                    Templates.replaceNode(destinationLoadingElement, '', '');
117
 
118
                    if (originElement) {
119
                        var originLoadingElement = originElement.find(SELECTORS.LOADING_ICON);
120
                        originElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');
121
                        Templates.replaceNode(originLoadingElement, '', '');
122
                    }
123
                    return;
124
                })
125
                .catch(Notification.exception);
126
        }
127
    };
128
 
129
    /**
130
     * Listen to and handle any calendar events fired by the calendar UI.
131
     *
132
     * @method registerCalendarEventListeners
133
     * @param {object} root The calendar root element
134
     * @param {object} eventFormModalPromise A promise reolved with the event form modal
135
     */
136
    var registerCalendarEventListeners = function(root, eventFormModalPromise) {
137
        var body = $('body');
138
 
139
        body.on(CalendarEvents.created, function() {
140
            CalendarViewManager.reloadCurrentMonth(root);
141
        });
142
        body.on(CalendarEvents.deleted, function() {
143
            CalendarViewManager.reloadCurrentMonth(root);
144
        });
145
        body.on(CalendarEvents.updated, function() {
146
            CalendarViewManager.reloadCurrentMonth(root);
147
        });
148
        body.on(CalendarEvents.editActionEvent, function(e, url) {
149
            // Action events needs to be edit directly on the course module.
150
            window.location.assign(url);
151
        });
152
        // Handle the event fired by the drag and drop code.
153
        body.on(CalendarEvents.moveEvent, handleMoveEvent);
154
        // When an event is successfully moved we should updated the UI.
155
        body.on(CalendarEvents.eventMoved, function() {
156
            CalendarViewManager.reloadCurrentMonth(root);
157
        });
158
        // Announce the newly loaded month to screen readers.
159
        body.on(CalendarEvents.monthChanged, root, async function() {
160
            const monthName = body.find(SELECTORS.CURRENT_MONTH).text();
161
            const monthAnnoucement = await Str.get_string('newmonthannouncement', 'calendar', monthName);
162
            body.find(SELECTORS.SCREEN_READER_ANNOUNCEMENTS).html(monthAnnoucement);
163
        });
164
 
165
        CalendarCrud.registerEditListeners(root, eventFormModalPromise);
166
    };
167
 
168
    /**
169
     * Register event listeners for the module.
170
     *
171
     * @param {object} root The calendar root element
11 efrain 172
     * @param {boolean} isCalendarBlock - A flag indicating whether this is a calendar block.
1 efrain 173
     */
11 efrain 174
    var registerEventListeners = function(root, isCalendarBlock) {
1 efrain 175
        const viewingFullCalendar = document.getElementById(CalendarSelectors.fullCalendarView);
176
        // Listen the click on the day link to render the day view.
177
        root.on('click', SELECTORS.VIEW_DAY_LINK, function(e) {
178
            var dayLink = $(e.target).closest(SELECTORS.VIEW_DAY_LINK);
179
            var year = dayLink.data('year'),
180
                month = dayLink.data('month'),
181
                day = dayLink.data('day'),
182
                courseId = dayLink.data('courseid'),
183
                categoryId = dayLink.data('categoryid');
184
            const urlParams = {
185
                view: 'day',
186
                time: dayLink.data('timestamp'),
187
                course: courseId,
188
            };
189
            if (viewingFullCalendar) {
190
                // Construct the URL parameter string from the urlParams object.
191
                const urlParamString = Object.entries(urlParams)
192
                    .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
193
                    .join('&');
194
                CalendarViewManager.refreshDayContent(root, year, month, day, courseId, categoryId, root,
11 efrain 195
                    'core_calendar/calendar_day', isCalendarBlock).then(function() {
1 efrain 196
                    e.preventDefault();
11 efrain 197
                    // Update the URL if it's not calendar block.
198
                    if (!isCalendarBlock) {
199
                        CalendarViewManager.updateUrl('?' + urlParamString);
200
                    }
201
                    return;
1 efrain 202
                }).catch(Notification.exception);
203
            } else {
204
                window.location.assign(Url.relativeUrl('calendar/view.php', urlParams));
205
            }
206
        });
207
 
208
        root.on('change', CalendarSelectors.elements.courseSelector, function() {
209
            var selectElement = $(this);
210
            var courseId = selectElement.val();
211
            const courseName = $("option:selected", selectElement).text();
212
            CalendarViewManager.reloadCurrentMonth(root, courseId, null)
213
                .then(function() {
214
                    // We need to get the selector again because the content has changed.
215
                    return root.find(CalendarSelectors.elements.courseSelector).val(courseId);
216
                })
217
                .then(function() {
218
                    CalendarViewManager.updateUrl('?view=month&course=' + courseId);
219
                    CalendarViewManager.handleCourseChange(Number(courseId), courseName);
220
                    return;
221
                })
222
                .catch(Notification.exception);
223
        });
224
 
225
        var eventFormPromise = CalendarCrud.registerEventFormModal(root),
226
            contextId = $(SELECTORS.CALENDAR_MONTH_WRAPPER).data('context-id');
227
        registerCalendarEventListeners(root, eventFormPromise);
228
 
229
        if (contextId) {
230
            // Bind click events to calendar days.
231
            root.on('click', SELECTORS.DAY, function(e) {
232
                var target = $(e.target);
233
                const displayingSmallBlockCalendar = root.parents('aside').data('blockregion') === 'side-pre';
234
 
235
                if (!viewingFullCalendar && displayingSmallBlockCalendar) {
236
                    const dateContainer = target.closest(SELECTORS.DAY);
237
                    const wrapper = target.closest(CalendarSelectors.wrapper);
238
                    const courseId = wrapper.data('courseid');
239
                    const params = {
240
                        view: 'day',
241
                        time: dateContainer.data('day-timestamp'),
242
                        course: courseId,
243
                    };
244
                    window.location.assign(Url.relativeUrl('calendar/view.php', params));
245
                } else {
246
                    const hasViewDayLink = target.closest(SELECTORS.VIEW_DAY_LINK).length;
247
                    const shouldShowNewEventModal = !hasViewDayLink;
248
                    if (shouldShowNewEventModal) {
249
                        var startTime = $(this).attr('data-new-event-timestamp');
250
                        eventFormPromise.then(function(modal) {
251
                            var wrapper = target.closest(CalendarSelectors.wrapper);
252
                            modal.setCourseId(wrapper.data('courseid'));
253
 
254
                            var categoryId = wrapper.data('categoryid');
255
                            if (typeof categoryId !== 'undefined') {
256
                                modal.setCategoryId(categoryId);
257
                            }
258
 
259
                            modal.setContextId(wrapper.data('contextId'));
260
                            modal.setStartTime(startTime);
261
                            modal.show();
262
                            return;
263
                        }).catch(Notification.exception);
264
                    }
265
                }
266
                e.preventDefault();
267
            });
268
        }
269
    };
270
 
271
    return {
11 efrain 272
        /**
273
         * Initializes the calendar view manager and registers event listeners.
274
         *
275
         * @param {HTMLElement} root - The root element where the calendar view manager and event listeners will be attached.
276
         * @param {boolean} [isCalendarBlock=false] - A flag indicating whether this is a calendar block.
277
         */
278
        init: function(root, isCalendarBlock = false) {
1 efrain 279
            root = $(root);
11 efrain 280
            CalendarViewManager.init(root, 'month', isCalendarBlock);
281
            registerEventListeners(root, isCalendarBlock);
1 efrain 282
        }
283
    };
284
});