Merge branch 'MDL-67152-master' of git://github.com/rezaies/moodle

This commit is contained in:
Andrew Nicols
2019-12-10 08:12:31 +08:00
10 changed files with 583 additions and 616 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
define ("core_calendar/repository",["jquery","core/ajax"],function(a,b){return{getEventById:function getEventById(a){return b.call([{methodname:"core_calendar_get_calendar_event_by_id",args:{eventid:a}}])[0]},deleteEvent:function deleteEvent(a,c){if("undefined"==typeof c){c=!1}var d={methodname:"core_calendar_delete_calendar_events",args:{events:[{eventid:a,repeat:c}]}};return b.call([d])[0]},updateEventStartDay:function updateEventStartDay(a,c){return b.call([{methodname:"core_calendar_update_event_start_day",args:{eventid:a,daytimestamp:c}}])[0]},submitCreateUpdateForm:function submitCreateUpdateForm(a){return b.call([{methodname:"core_calendar_submit_create_update_form",args:{formdata:a}}])[0]},getCalendarMonthData:function getCalendarMonthData(a,c,d,e,f,g){return b.call([{methodname:"core_calendar_get_calendar_monthly_view",args:{year:a,month:c,courseid:d,categoryid:e,includenavigation:f,mini:g}}])[0]},getCalendarDayData:function getCalendarDayData(a,c,d,e,f){return b.call([{methodname:"core_calendar_get_calendar_day_view",args:{year:a,month:c,day:d,courseid:e,categoryid:f}}])[0]},getCalendarUpcomingData:function getCalendarUpcomingData(a,c){return b.call([{methodname:"core_calendar_get_calendar_upcoming_view",args:{courseid:a,categoryid:c}}])[0]},getCourseGroupsData:function getCourseGroupsData(a){return b.call([{methodname:"core_group_get_course_groups",args:{courseid:a}}])[0]}}});
define ("core_calendar/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.getCourseGroupsData=a.getCalendarUpcomingData=a.updateEventStartDay=a.getCalendarDayData=a.getCalendarMonthData=a.submitCreateUpdateForm=a.getEventById=a.deleteEvent=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c=function(a){var c=1<arguments.length&&arguments[1]!==void 0?arguments[1]:!1;return b.default.call([{methodname:"core_calendar_delete_calendar_events",args:{events:[{eventid:a,repeat:c}]}}])[0]};a.deleteEvent=c;var d=function(a){return b.default.call([{methodname:"core_calendar_get_calendar_event_by_id",args:{eventid:a}}])[0]};a.getEventById=d;var e=function(a){return b.default.call([{methodname:"core_calendar_submit_create_update_form",args:{formdata:a}}])[0]};a.submitCreateUpdateForm=e;var f=function(a,c,d,e,f,g){var h=6<arguments.length&&arguments[6]!==void 0?arguments[6]:1;return b.default.call([{methodname:"core_calendar_get_calendar_monthly_view",args:{year:a,month:c,courseid:d,categoryid:e,includenavigation:f,mini:g,day:h}}])[0]};a.getCalendarMonthData=f;var g=function(a,c,d,e,f){return b.default.call([{methodname:"core_calendar_get_calendar_day_view",args:{year:a,month:c,day:d,courseid:e,categoryid:f}}])[0]};a.getCalendarDayData=g;var h=function(a,c){return b.default.call([{methodname:"core_calendar_update_event_start_day",args:{eventid:a,daytimestamp:c}}])[0]};a.updateEventStartDay=h;var i=function(a,c){return b.default.call([{methodname:"core_calendar_get_calendar_upcoming_view",args:{courseid:a,categoryid:c}}])[0]};a.getCalendarUpcomingData=i;var j=function(a){return b.default.call([{methodname:"core_group_get_course_groups",args:{courseid:a}}])[0]};a.getCourseGroupsData=j});
//# sourceMappingURL=repository.min.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+163 -176
View File
@@ -22,190 +22,177 @@
* @copyright 2017 Simey Lameze <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/ajax'], function($, Ajax) {
import Ajax from 'core/ajax';
/**
* Delete a calendar event.
*
* @method deleteEvent
* @param {int} eventId The event id.
* @param {bool} deleteSeries Whether to delete all events in the series
* @return {promise} Resolved with requested calendar event
*/
var deleteEvent = function(eventId, deleteSeries) {
if (typeof deleteSeries === 'undefined') {
deleteSeries = false;
}
var request = {
methodname: 'core_calendar_delete_calendar_events',
args: {
events: [{
eventid: eventId,
repeat: deleteSeries,
}]
}
};
return Ajax.call([request])[0];
};
/**
* Get a calendar event by id.
*
* @method getEventById
* @param {int} eventId The event id.
* @return {promise} Resolved with requested calendar event
*/
var getEventById = function(eventId) {
var request = {
methodname: 'core_calendar_get_calendar_event_by_id',
args: {
eventid: eventId
}
};
return Ajax.call([request])[0];
};
/**
* Submit the form data for the event form.
*
* @method submitCreateUpdateForm
* @param {string} formdata The URL encoded values from the form
* @return {promise} Resolved with the new or edited event
*/
var submitCreateUpdateForm = function(formdata) {
var request = {
methodname: 'core_calendar_submit_create_update_form',
args: {
formdata: formdata
}
};
return Ajax.call([request])[0];
};
/**
* Get calendar data for the month view.
*
* @method getCalendarMonthData
* @param {Number} year Year
* @param {Number} month Month
* @param {Number} courseid The course id.
* @param {Number} categoryid The category id.
* @param {Bool} includenavigation Whether to include navigation.
* @param {Bool} mini Whether the month is in mini view.
* @return {promise} Resolved with the month view data.
*/
var getCalendarMonthData = function(year, month, courseid, categoryid, includenavigation, mini) {
var request = {
methodname: 'core_calendar_get_calendar_monthly_view',
args: {
year: year,
month: month,
courseid: courseid,
categoryid: categoryid,
includenavigation: includenavigation,
mini: mini
}
};
return Ajax.call([request])[0];
};
/**
* Get calendar data for the day view.
*
* @method getCalendarDayData
* @param {Number} year Year
* @param {Number} month Month
* @param {Number} day Day
* @param {Number} courseid The course id.
* @param {Number} categoryId The id of the category whose events are shown
* @return {promise} Resolved with the day view data.
*/
var getCalendarDayData = function(year, month, day, courseid, categoryId) {
var request = {
methodname: 'core_calendar_get_calendar_day_view',
args: {
year: year,
month: month,
day: day,
courseid: courseid,
categoryid: categoryId,
}
};
return Ajax.call([request])[0];
};
/**
* Change the start day for the given event id. The day timestamp
* only has to be any time during the target day because only the
* date information is extracted, the time of the day is ignored.
*
* @param {int} eventId The id of the event to update
* @param {int} dayTimestamp A timestamp for some time during the target day
* @return {promise}
*/
var updateEventStartDay = function(eventId, dayTimestamp) {
var request = {
methodname: 'core_calendar_update_event_start_day',
args: {
/**
* Delete a calendar event.
*
* @method deleteEvent
* @param {number} eventId The event id.
* @param {boolean} deleteSeries Whether to delete all events in the series
* @return {promise} Resolved with requested calendar event
*/
export const deleteEvent = (eventId, deleteSeries = false) => {
const request = {
methodname: 'core_calendar_delete_calendar_events',
args: {
events: [{
eventid: eventId,
daytimestamp: dayTimestamp
}
};
return Ajax.call([request])[0];
repeat: deleteSeries,
}]
}
};
/**
* Get calendar upcoming data.
*
* @method getCalendarUpcomingData
* @param {Number} courseid The course id.
* @param {Number} categoryid The category id.
* @return {promise} Resolved with the month view data.
*/
var getCalendarUpcomingData = function(courseid, categoryid) {
var request = {
methodname: 'core_calendar_get_calendar_upcoming_view',
args: {
courseid: courseid,
categoryid: categoryid,
}
};
return Ajax.call([request])[0];
};
return Ajax.call([request])[0];
/**
* Get a calendar event by id.
*
* @method getEventById
* @param {number} eventId The event id.
* @return {promise} Resolved with requested calendar event
*/
export const getEventById = (eventId) => {
const request = {
methodname: 'core_calendar_get_calendar_event_by_id',
args: {
eventid: eventId
}
};
/**
* Get the groups by course id.
*
* @param {Number} courseid The course id to fetch the groups from.
* @return {promise} Resolved with the course groups.
*/
var getCourseGroupsData = function(courseid) {
var request = {
methodname: 'core_group_get_course_groups',
args: {
courseid: courseid
}
};
return Ajax.call([request])[0];
};
return Ajax.call([request])[0];
/**
* Submit the form data for the event form.
*
* @method submitCreateUpdateForm
* @param {string} formData The URL encoded values from the form
* @return {promise} Resolved with the new or edited event
*/
export const submitCreateUpdateForm = (formData) => {
const request = {
methodname: 'core_calendar_submit_create_update_form',
args: {
formdata: formData
}
};
return {
getEventById: getEventById,
deleteEvent: deleteEvent,
updateEventStartDay: updateEventStartDay,
submitCreateUpdateForm: submitCreateUpdateForm,
getCalendarMonthData: getCalendarMonthData,
getCalendarDayData: getCalendarDayData,
getCalendarUpcomingData: getCalendarUpcomingData,
getCourseGroupsData: getCourseGroupsData
return Ajax.call([request])[0];
};
/**
* Get calendar data for the month view.
*
* @method getCalendarMonthData
* @param {number} year Year
* @param {number} month Month
* @param {number} courseId The course id.
* @param {number} categoryId The category id.
* @param {boolean} includeNavigation Whether to include navigation.
* @param {boolean} mini Whether the month is in mini view.
* @param {number} day Day (optional)
* @return {promise} Resolved with the month view data.
*/
export const getCalendarMonthData = (year, month, courseId, categoryId, includeNavigation, mini, day = 1) => {
const request = {
methodname: 'core_calendar_get_calendar_monthly_view',
args: {
year,
month,
courseid: courseId,
categoryid: categoryId,
includenavigation: includeNavigation,
mini,
day,
}
};
});
return Ajax.call([request])[0];
};
/**
* Get calendar data for the day view.
*
* @method getCalendarDayData
* @param {number} year Year
* @param {number} month Month
* @param {number} day Day
* @param {number} courseId The course id.
* @param {number} categoryId The id of the category whose events are shown
* @return {promise} Resolved with the day view data.
*/
export const getCalendarDayData = (year, month, day, courseId, categoryId) => {
const request = {
methodname: 'core_calendar_get_calendar_day_view',
args: {
year,
month,
day,
courseid: courseId,
categoryid: categoryId,
}
};
return Ajax.call([request])[0];
};
/**
* Change the start day for the given event id. The day timestamp
* only has to be any time during the target day because only the
* date information is extracted, the time of the day is ignored.
*
* @param {int} eventId The id of the event to update
* @param {int} dayTimestamp A timestamp for some time during the target day
* @return {promise}
*/
export const updateEventStartDay = (eventId, dayTimestamp) => {
const request = {
methodname: 'core_calendar_update_event_start_day',
args: {
eventid: eventId,
daytimestamp: dayTimestamp
}
};
return Ajax.call([request])[0];
};
/**
* Get calendar upcoming data.
*
* @method getCalendarUpcomingData
* @param {number} courseId The course id.
* @param {number} categoryId The category id.
* @return {promise} Resolved with the month view data.
*/
export const getCalendarUpcomingData = (courseId, categoryId) => {
const request = {
methodname: 'core_calendar_get_calendar_upcoming_view',
args: {
courseid: courseId,
categoryid: categoryId,
}
};
return Ajax.call([request])[0];
};
/**
* Get the groups by course id.
*
* @param {Number} courseId The course id to fetch the groups from.
* @return {promise} Resolved with the course groups.
*/
export const getCourseGroupsData = (courseId) => {
const request = {
methodname: 'core_group_get_course_groups',
args: {
courseid: courseId
}
};
return Ajax.call([request])[0];
};
+389 -429
View File
@@ -21,441 +21,401 @@
* @copyright 2017 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/templates',
'core/str',
'core/notification',
'core_calendar/repository',
'core_calendar/events',
'core_calendar/selectors',
'core/modal_factory',
'core/modal_events',
'core_calendar/summary_modal',
'core/custom_interaction_events',
], function(
$,
Templates,
Str,
Notification,
CalendarRepository,
CalendarEvents,
CalendarSelectors,
ModalFactory,
ModalEvents,
SummaryModal,
CustomEvents
) {
/**
* Register event listeners for the module.
*
* @param {object} root The root element.
*/
var registerEventListeners = function(root) {
root = $(root);
import $ from 'jquery';
import Templates from 'core/templates';
import Notification from 'core/notification';
import * as CalendarRepository from 'core_calendar/repository';
import CalendarEvents from 'core_calendar/events';
import * as CalendarSelectors from 'core_calendar/selectors';
import ModalFactory from 'core/modal_factory';
import ModalEvents from 'core/modal_events';
import SummaryModal from 'core_calendar/summary_modal';
import CustomEvents from 'core/custom_interaction_events';
// Bind click events to event links.
root.on('click', CalendarSelectors.links.eventLink, function(e) {
var target = $(e.target);
var eventId = null;
/**
* Register event listeners for the module.
*
* @param {object} root The root element.
*/
const registerEventListeners = (root) => {
root = $(root);
var eventLink;
if (target.is(CalendarSelectors.actions.viewEvent)) {
eventLink = target;
} else {
eventLink = target.closest(CalendarSelectors.actions.viewEvent);
}
// Bind click events to event links.
root.on('click', CalendarSelectors.links.eventLink, (e) => {
const target = e.target;
let eventLink = null;
let eventId = null;
if (eventLink.length) {
eventId = eventLink.data('eventId');
} else {
eventId = target.find(CalendarSelectors.actions.viewEvent).data('eventId');
}
if (target.matches(CalendarSelectors.actions.viewEvent)) {
eventLink = target;
} else {
eventLink = target.closest(CalendarSelectors.actions.viewEvent);
}
if (eventId) {
// A link was found. Show the modal.
if (eventLink) {
eventId = eventLink.dataset.eventId;
} else {
eventId = target.querySelector(CalendarSelectors.actions.viewEvent).dataset.eventId;
}
e.preventDefault();
// We've handled the event so stop it from bubbling
// and causing the day click handler to fire.
e.stopPropagation();
if (eventId) {
// A link was found. Show the modal.
renderEventSummaryModal(eventId);
}
});
e.preventDefault();
// We've handled the event so stop it from bubbling
// and causing the day click handler to fire.
e.stopPropagation();
root.on('click', CalendarSelectors.links.navLink, function(e) {
var wrapper = root.find(CalendarSelectors.wrapper);
var view = wrapper.data('view');
var courseId = wrapper.data('courseid');
var categoryId = wrapper.data('categoryid');
var link = $(e.currentTarget);
if (view === 'month') {
changeMonth(root, link.attr('href'), link.data('year'), link.data('month'), courseId, categoryId);
e.preventDefault();
} else if (view === 'day') {
changeDay(root, link.attr('href'), link.data('year'), link.data('month'), link.data('day'),
courseId, categoryId);
e.preventDefault();
}
});
var viewSelector = root.find(CalendarSelectors.viewSelector);
CustomEvents.define(viewSelector, [CustomEvents.events.activate]);
viewSelector.on(
CustomEvents.events.activate,
function(e) {
e.preventDefault();
var option = $(e.target);
if (option.hasClass('active')) {
return;
}
var view = option.data('view'),
year = option.data('year'),
month = option.data('month'),
day = option.data('day'),
courseId = option.data('courseid'),
categoryId = option.data('categoryid');
if (view == 'month') {
refreshMonthContent(root, year, month, courseId, categoryId, root, 'core_calendar/calendar_month')
.then(function() {
return window.history.pushState({}, '', '?view=month');
}).fail(Notification.exception);
} else if (view == 'day') {
refreshDayContent(root, year, month, day, courseId, categoryId, root, 'core_calendar/calendar_day')
.then(function() {
return window.history.pushState({}, '', '?view=day');
}).fail(Notification.exception);
} else if (view == 'upcoming') {
reloadCurrentUpcoming(root, courseId, categoryId, root, 'core_calendar/calendar_upcoming')
.then(function() {
return window.history.pushState({}, '', '?view=upcoming');
}).fail(Notification.exception);
}
}
);
};
/**
* Refresh the month content.
*
* @param {object} root The root element.
* @param {Number} year Year
* @param {Number} month Month
* @param {Number} courseid The id of the course whose events are shown
* @param {Number} categoryid The id of the category whose events are shown
* @param {object} target The element being replaced. If not specified, the calendarwrapper is used.
* @param {String} template The template to be rendered.
* @return {promise}
*/
var refreshMonthContent = function(root, year, month, courseid, categoryid, target, template) {
startLoading(root);
target = target || root.find(CalendarSelectors.wrapper);
template = template || root.attr('data-template');
M.util.js_pending([root.get('id'), year, month, courseid].join('-'));
var includenavigation = root.data('includenavigation');
var mini = root.data('mini');
return CalendarRepository.getCalendarMonthData(year, month, courseid, categoryid, includenavigation, mini)
.then(function(context) {
context.viewingmonth = true;
return Templates.render(template, context);
})
.then(function(html, js) {
return Templates.replaceNode(target, html, js);
})
.then(function() {
$('body').trigger(CalendarEvents.viewUpdated);
return;
})
.always(function() {
M.util.js_complete([root.get('id'), year, month, courseid].join('-'));
return stopLoading(root);
})
.fail(Notification.exception);
};
/**
* Handle changes to the current calendar view.
*
* @param {object} root The container element
* @param {String} url The calendar url to be shown
* @param {Number} year Year
* @param {Number} month Month
* @param {Number} courseid The id of the course whose events are shown
* @param {Number} categoryid The id of the category whose events are shown
* @return {promise}
*/
var changeMonth = function(root, url, year, month, courseid, categoryid) {
return refreshMonthContent(root, year, month, courseid, categoryid)
.then(function() {
if (url.length && url !== '#') {
window.history.pushState({}, '', url);
}
return arguments;
})
.then(function() {
$('body').trigger(CalendarEvents.monthChanged, [year, month, courseid, categoryid]);
return arguments;
});
};
/**
* Reload the current month view data.
*
* @param {object} root The container element.
* @param {Number} courseId The course id.
* @param {Number} categoryId The id of the category whose events are shown
* @return {promise}
*/
var reloadCurrentMonth = function(root, courseId, categoryId) {
var year = root.find(CalendarSelectors.wrapper).data('year');
var month = root.find(CalendarSelectors.wrapper).data('month');
if (typeof courseId === 'undefined') {
courseId = root.find(CalendarSelectors.wrapper).data('courseid');
}
if (typeof categoryId === 'undefined') {
categoryId = root.find(CalendarSelectors.wrapper).data('categoryid');
}
return refreshMonthContent(root, year, month, courseId, categoryId);
};
/**
* Refresh the day content.
*
* @param {object} root The root element.
* @param {Number} year Year
* @param {Number} month Month
* @param {Number} day Day
* @param {Number} courseid The id of the course whose events are shown
* @param {Number} categoryId The id of the category whose events are shown
* @param {object} target The element being replaced. If not specified, the calendarwrapper is used.
* @param {String} template The template to be rendered.
*
* @return {promise}
*/
var refreshDayContent = function(root, year, month, day, courseid, categoryId, target, template) {
startLoading(root);
target = target || root.find(CalendarSelectors.wrapper);
template = template || root.attr('data-template');
M.util.js_pending([root.get('id'), year, month, day, courseid, categoryId].join('-'));
var includenavigation = root.data('includenavigation');
return CalendarRepository.getCalendarDayData(year, month, day, courseid, categoryId, includenavigation)
.then(function(context) {
context.viewingday = true;
return Templates.render(template, context);
})
.then(function(html, js) {
return Templates.replaceNode(target, html, js);
})
.then(function() {
$('body').trigger(CalendarEvents.viewUpdated);
return;
})
.always(function() {
M.util.js_complete([root.get('id'), year, month, day, courseid, categoryId].join('-'));
return stopLoading(root);
})
.fail(Notification.exception);
};
/**
* Reload the current day view data.
*
* @param {object} root The container element.
* @param {Number} courseId The course id.
* @param {Number} categoryId The id of the category whose events are shown
* @return {promise}
*/
var reloadCurrentDay = function(root, courseId, categoryId) {
var wrapper = root.find(CalendarSelectors.wrapper);
var year = wrapper.data('year');
var month = wrapper.data('month');
var day = wrapper.data('day');
if (!courseId) {
courseId = root.find(CalendarSelectors.wrapper).data('courseid');
}
if (typeof categoryId === 'undefined') {
categoryId = root.find(CalendarSelectors.wrapper).data('categoryid');
}
return refreshDayContent(root, year, month, day, courseId, categoryId);
};
/**
* Handle changes to the current calendar view.
*
* @param {object} root The root element.
* @param {String} url The calendar url to be shown
* @param {Number} year Year
* @param {Number} month Month
* @param {Number} day Day
* @param {Number} courseId The id of the course whose events are shown
* @param {Number} categoryId The id of the category whose events are shown
* @return {promise}
*/
var changeDay = function(root, url, year, month, day, courseId, categoryId) {
return refreshDayContent(root, year, month, day, courseId, categoryId)
.then(function() {
if (url.length && url !== '#') {
window.history.pushState({}, '', url);
}
return arguments;
})
.then(function() {
$('body').trigger(CalendarEvents.dayChanged, [year, month, courseId, categoryId]);
return arguments;
});
};
/**
* Set the element state to loading.
*
* @param {object} root The container element
* @method startLoading
*/
var startLoading = function(root) {
var loadingIconContainer = root.find(CalendarSelectors.containers.loadingIcon);
loadingIconContainer.removeClass('hidden');
};
/**
* Remove the loading state from the element.
*
* @param {object} root The container element
* @method stopLoading
*/
var stopLoading = function(root) {
var loadingIconContainer = root.find(CalendarSelectors.containers.loadingIcon);
loadingIconContainer.addClass('hidden');
};
/**
* Reload the current month view data.
*
* @param {object} root The container element.
* @param {Number} courseId The course id.
* @param {Number} categoryId The id of the category whose events are shown
* @param {String} template The template to be rendered.
* @param {object} target The element being replaced. If not specified, the calendarwrapper is used.
* @return {promise}
*/
var reloadCurrentUpcoming = function(root, courseId, categoryId, target, template) {
startLoading(root);
target = target || root.find(CalendarSelectors.wrapper);
template = template || root.attr('data-template');
if (typeof courseId === 'undefined') {
courseId = root.find(CalendarSelectors.wrapper).data('courseid');
}
if (typeof categoryId === 'undefined') {
categoryId = root.find(CalendarSelectors.wrapper).data('categoryid');
}
return CalendarRepository.getCalendarUpcomingData(courseId, categoryId)
.then(function(context) {
context.viewingupcoming = true;
return Templates.render(template, context);
})
.then(function(html, js) {
return Templates.replaceNode(target, html, js);
})
.then(function() {
$('body').trigger(CalendarEvents.viewUpdated);
return;
})
.always(function() {
return stopLoading(root);
})
.fail(Notification.exception);
};
/**
* Get the CSS class to apply for the given event type.
*
* @param {String} eventType The calendar event type
* @return {String}
*/
var getEventTypeClassFromType = function(eventType) {
return 'calendar_event_' + eventType;
};
/**
* Render the event summary modal.
*
* @param {Number} eventId The calendar event id.
*/
var renderEventSummaryModal = function(eventId) {
var typeClass = '';
// Calendar repository promise.
CalendarRepository.getEventById(eventId).then(function(getEventResponse) {
if (!getEventResponse.event) {
throw new Error('Error encountered while trying to fetch calendar event with ID: ' + eventId);
}
var eventData = getEventResponse.event;
typeClass = getEventTypeClassFromType(eventData.normalisedeventtype);
return eventData;
}).then(function(eventData) {
// Build the modal parameters from the event data.
var modalParams = {
title: eventData.name,
type: SummaryModal.TYPE,
body: Templates.render('core_calendar/event_summary_body', eventData),
templateContext: {
canedit: eventData.canedit,
candelete: eventData.candelete,
headerclasses: typeClass,
isactionevent: eventData.isactionevent,
url: eventData.url
}
};
// Create the modal.
return ModalFactory.create(modalParams);
}).done(function(modal) {
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
// Finally, render the modal!
modal.show();
}).fail(Notification.exception);
};
return {
init: function(root, view) {
registerEventListeners(root, view);
},
reloadCurrentMonth: reloadCurrentMonth,
changeMonth: changeMonth,
refreshMonthContent: refreshMonthContent,
reloadCurrentDay: reloadCurrentDay,
changeDay: changeDay,
refreshDayContent: refreshDayContent,
reloadCurrentUpcoming: reloadCurrentUpcoming
};
renderEventSummaryModal(eventId);
}
});
root.on('click', CalendarSelectors.links.navLink, (e) => {
const wrapper = root.find(CalendarSelectors.wrapper);
const view = wrapper.data('view');
const courseId = wrapper.data('courseid');
const categoryId = wrapper.data('categoryid');
const link = e.currentTarget;
if (view === 'month') {
changeMonth(root, link.href, link.dataset.year, link.dataset.month, courseId, categoryId, link.dataset.day);
e.preventDefault();
} else if (view === 'day') {
changeDay(root, link.href, link.dataset.year, link.dataset.month, link.dataset.day, courseId, categoryId);
e.preventDefault();
}
});
const viewSelector = root.find(CalendarSelectors.viewSelector);
CustomEvents.define(viewSelector, [CustomEvents.events.activate]);
viewSelector.on(
CustomEvents.events.activate,
(e) => {
e.preventDefault();
const option = e.target;
if (option.classList.contains('active')) {
return;
}
const view = option.dataset.view,
year = option.dataset.year,
month = option.dataset.month,
day = option.dataset.day,
courseId = option.dataset.courseid,
categoryId = option.dataset.categoryid;
if (view == 'month') {
refreshMonthContent(root, year, month, courseId, categoryId, root, 'core_calendar/calendar_month', day)
.then(() => {
return window.history.pushState({}, '', '?view=month');
}).fail(Notification.exception);
} else if (view == 'day') {
refreshDayContent(root, year, month, day, courseId, categoryId, root, 'core_calendar/calendar_day')
.then(() => {
return window.history.pushState({}, '', '?view=day');
}).fail(Notification.exception);
} else if (view == 'upcoming') {
reloadCurrentUpcoming(root, courseId, categoryId, root, 'core_calendar/calendar_upcoming')
.then(() => {
return window.history.pushState({}, '', '?view=upcoming');
}).fail(Notification.exception);
}
}
);
};
/**
* Refresh the month content.
*
* @param {object} root The root element.
* @param {number} year Year
* @param {number} month Month
* @param {number} courseId The id of the course whose events are shown
* @param {number} categoryId The id of the category whose events are shown
* @param {object} target The element being replaced. If not specified, the calendarwrapper is used.
* @param {string} template The template to be rendered.
* @param {number} day Day (optional)
* @return {promise}
*/
export const refreshMonthContent = (root, year, month, courseId, categoryId, target = null, template = '', day = 1) => {
startLoading(root);
target = target || root.find(CalendarSelectors.wrapper);
template = template || root.attr('data-template');
M.util.js_pending([root.get('id'), year, month, courseId].join('-'));
const includenavigation = root.data('includenavigation');
const mini = root.data('mini');
return CalendarRepository.getCalendarMonthData(year, month, courseId, categoryId, includenavigation, mini, day)
.then(context => {
context.viewingmonth = true;
return Templates.render(template, context);
})
.then((html, js) => {
return Templates.replaceNode(target, html, js);
})
.then(() => {
document.querySelector('body').dispatchEvent(new Event(CalendarEvents.viewUpdated));
return;
})
.always(() => {
M.util.js_complete([root.get('id'), year, month, courseId].join('-'));
return stopLoading(root);
})
.fail(Notification.exception);
};
/**
* Handle changes to the current calendar view.
*
* @param {object} root The container element
* @param {string} url The calendar url to be shown
* @param {number} year Year
* @param {number} month Month
* @param {number} courseId The id of the course whose events are shown
* @param {number} categoryId The id of the category whose events are shown
* @param {number} day Day (optional)
* @return {promise}
*/
export const changeMonth = (root, url, year, month, courseId, categoryId, day = 1) => {
return refreshMonthContent(root, year, month, courseId, categoryId, null, '', day)
.then((...args) => {
if (url.length && url !== '#') {
window.history.pushState({}, '', url);
}
return args;
})
.then((...args) => {
$('body').trigger(CalendarEvents.monthChanged, [year, month, courseId, categoryId]);
return args;
});
};
/**
* Reload the current month view data.
*
* @param {object} root The container element.
* @param {number} courseId The course id.
* @param {number} categoryId The id of the category whose events are shown
* @return {promise}
*/
export const reloadCurrentMonth = (root, courseId = 0, categoryId = 0) => {
const year = root.find(CalendarSelectors.wrapper).data('year');
const month = root.find(CalendarSelectors.wrapper).data('month');
const day = root.find(CalendarSelectors.wrapper).data('day');
courseId = courseId || root.find(CalendarSelectors.wrapper).data('courseid');
categoryId = categoryId || root.find(CalendarSelectors.wrapper).data('categoryid');
return refreshMonthContent(root, year, month, courseId, categoryId, null, '', day);
};
/**
* Refresh the day content.
*
* @param {object} root The root element.
* @param {number} year Year
* @param {number} month Month
* @param {number} day Day
* @param {number} courseId The id of the course whose events are shown
* @param {number} categoryId The id of the category whose events are shown
* @param {object} target The element being replaced. If not specified, the calendarwrapper is used.
* @param {string} template The template to be rendered.
*
* @return {promise}
*/
export const refreshDayContent = (root, year, month, day, courseId, categoryId, target = null, template = '') => {
startLoading(root);
target = target || root.find(CalendarSelectors.wrapper);
template = template || root.attr('data-template');
M.util.js_pending([root.get('id'), year, month, day, courseId, categoryId].join('-'));
const includenavigation = root.data('includenavigation');
return CalendarRepository.getCalendarDayData(year, month, day, courseId, categoryId, includenavigation)
.then((context) => {
context.viewingday = true;
return Templates.render(template, context);
})
.then((html, js) => {
return Templates.replaceNode(target, html, js);
})
.then(() => {
document.querySelector('body').dispatchEvent(new Event(CalendarEvents.viewUpdated));
return;
})
.always(() => {
M.util.js_complete([root.get('id'), year, month, day, courseId, categoryId].join('-'));
return stopLoading(root);
})
.fail(Notification.exception);
};
/**
* Reload the current day view data.
*
* @param {object} root The container element.
* @param {number} courseId The course id.
* @param {number} categoryId The id of the category whose events are shown
* @return {promise}
*/
export const reloadCurrentDay = (root, courseId = 0, categoryId = 0) => {
const wrapper = root.find(CalendarSelectors.wrapper);
const year = wrapper.data('year');
const month = wrapper.data('month');
const day = wrapper.data('day');
courseId = courseId || root.find(CalendarSelectors.wrapper).data('courseid');
categoryId = categoryId || root.find(CalendarSelectors.wrapper).data('categoryid');
return refreshDayContent(root, year, month, day, courseId, categoryId);
};
/**
* Handle changes to the current calendar view.
*
* @param {object} root The root element.
* @param {String} url The calendar url to be shown
* @param {Number} year Year
* @param {Number} month Month
* @param {Number} day Day
* @param {Number} courseId The id of the course whose events are shown
* @param {Number} categoryId The id of the category whose events are shown
* @return {promise}
*/
export const changeDay = (root, url, year, month, day, courseId, categoryId) => {
return refreshDayContent(root, year, month, day, courseId, categoryId)
.then((...args) => {
if (url.length && url !== '#') {
window.history.pushState({}, '', url);
}
return args;
})
.then((...args) => {
$('body').trigger(CalendarEvents.dayChanged, [year, month, courseId, categoryId]);
return args;
});
};
/**
* Set the element state to loading.
*
* @param {object} root The container element
* @method startLoading
*/
const startLoading = (root) => {
const loadingIconContainer = root.find(CalendarSelectors.containers.loadingIcon);
loadingIconContainer.removeClass('hidden');
};
/**
* Remove the loading state from the element.
*
* @param {object} root The container element
* @method stopLoading
*/
const stopLoading = (root) => {
const loadingIconContainer = root.find(CalendarSelectors.containers.loadingIcon);
loadingIconContainer.addClass('hidden');
};
/**
* Reload the current month view data.
*
* @param {object} root The container element.
* @param {number} courseId The course id.
* @param {number} categoryId The id of the category whose events are shown
* @param {string} template The template to be rendered.
* @param {object} target The element being replaced. If not specified, the calendarwrapper is used.
* @return {promise}
*/
export const reloadCurrentUpcoming = (root, courseId = 0, categoryId = 0, target = null, template = '') => {
startLoading(root);
target = target || root.find(CalendarSelectors.wrapper);
template = template || root.attr('data-template');
courseId = courseId || root.find(CalendarSelectors.wrapper).data('courseid');
categoryId = categoryId || root.find(CalendarSelectors.wrapper).data('categoryid');
return CalendarRepository.getCalendarUpcomingData(courseId, categoryId)
.then((context) => {
context.viewingupcoming = true;
return Templates.render(template, context);
})
.then((html, js) => {
return Templates.replaceNode(target, html, js);
})
.then(() => {
document.querySelector('body').dispatchEvent(new Event(CalendarEvents.viewUpdated));
return;
})
.always(function() {
return stopLoading(root);
})
.fail(Notification.exception);
};
/**
* Get the CSS class to apply for the given event type.
*
* @param {string} eventType The calendar event type
* @return {string}
*/
const getEventTypeClassFromType = (eventType) => {
return 'calendar_event_' + eventType;
};
/**
* Render the event summary modal.
*
* @param {Number} eventId The calendar event id.
*/
const renderEventSummaryModal = (eventId) => {
let typeClass = '';
// Calendar repository promise.
CalendarRepository.getEventById(eventId).then((getEventResponse) => {
if (!getEventResponse.event) {
throw new Error('Error encountered while trying to fetch calendar event with ID: ' + eventId);
}
const eventData = getEventResponse.event;
typeClass = getEventTypeClassFromType(eventData.normalisedeventtype);
return eventData;
}).then((eventData) => {
// Build the modal parameters from the event data.
const modalParams = {
title: eventData.name,
type: SummaryModal.TYPE,
body: Templates.render('core_calendar/event_summary_body', eventData),
templateContext: {
canedit: eventData.canedit,
candelete: eventData.candelete,
headerclasses: typeClass,
isactionevent: eventData.isactionevent,
url: eventData.url
}
};
// Create the modal.
return ModalFactory.create(modalParams);
}).done(function(modal) {
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
// Finally, render the modal!
modal.show();
}).fail(Notification.exception);
};
export const init = (root, view) => {
registerEventListeners(root, view);
};
+6 -3
View File
@@ -988,10 +988,11 @@ class core_calendar_external extends external_api {
* @param int $categoryid The category to be included
* @param bool $includenavigation Whether to include navigation
* @param bool $mini Whether to return the mini month view or not
* @param int $day The day we want to keep as the current day
* @return array
*/
public static function get_calendar_monthly_view($year, $month, $courseid, $categoryid, $includenavigation, $mini) {
global $DB, $USER, $PAGE;
public static function get_calendar_monthly_view($year, $month, $courseid, $categoryid, $includenavigation, $mini, $day) {
global $USER, $PAGE;
// Parameter validation.
$params = self::validate_parameters(self::get_calendar_monthly_view_parameters(), [
@@ -1001,6 +1002,7 @@ class core_calendar_external extends external_api {
'categoryid' => $categoryid,
'includenavigation' => $includenavigation,
'mini' => $mini,
'day' => $day,
]);
$context = \context_user::instance($USER->id);
@@ -1009,7 +1011,7 @@ class core_calendar_external extends external_api {
$type = \core_calendar\type_factory::get_calendar_instance();
$time = $type->convert_to_timestamp($params['year'], $params['month'], 1);
$time = $type->convert_to_timestamp($params['year'], $params['month'], $params['day']);
$calendar = \calendar_information::create($time, $params['courseid'], $params['categoryid']);
self::validate_context($calendar->context);
@@ -1045,6 +1047,7 @@ class core_calendar_external extends external_api {
false,
NULL_ALLOWED
),
'day' => new external_value(PARAM_INT, 'Day to be viewed', VALUE_DEFAULT, 1),
]
);
}
+1
View File
@@ -38,6 +38,7 @@
}} data-categoryid="{{categoryid}}"{{!
}} data-month="{{date.mon}}"{{!
}} data-year="{{date.year}}"{{!
}} data-day="{{date.mday}}"{{!
}} data-view="month"{{!
}}>
{{> core/overlay_loading}}
+19 -3
View File
@@ -2372,7 +2372,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
$data = external_api::clean_returnvalue(
core_calendar_external::get_calendar_monthly_view_returns(),
core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
$course->id, null, false, true)
$course->id, null, false, true, $timestart->format('d'))
);
$this->assertEquals($data['courseid'], $course->id);
// User enrolled in the course can load the course calendar.
@@ -2380,7 +2380,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
$data = external_api::clean_returnvalue(
core_calendar_external::get_calendar_monthly_view_returns(),
core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
$course->id, null, false, true)
$course->id, null, false, true, $timestart->format('d'))
);
$this->assertEquals($data['courseid'], $course->id);
// User not enrolled in the course cannot load the course calendar.
@@ -2389,10 +2389,26 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
$data = external_api::clean_returnvalue(
core_calendar_external::get_calendar_monthly_view_returns(),
core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
$course->id, null, false, false)
$course->id, null, false, false, $timestart->format('d'))
);
}
/**
* Test get_calendar_monthly_view when a day parameter is provided.
*/
public function test_get_calendar_monthly_view_with_day_provided() {
$this->resetAfterTest();
$this->setAdminUser();
$timestart = new DateTime();
$data = external_api::clean_returnvalue(
core_calendar_external::get_calendar_monthly_view_returns(),
core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
SITEID, null, false, true, $timestart->format('d'))
);
$this->assertEquals($data['date']['mday'], $timestart->format('d'));
}
/**
* A user should not be able load the calendar day view for a course they cannot access.
*/
+1 -1
View File
@@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2019120500.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2019120500.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '3.9dev (Build: 20191205)'; // Human-friendly version name