diff --git a/calendar/amd/build/repository.min.js b/calendar/amd/build/repository.min.js
index 55d3e1e34b6..e04ceb50e4d 100644
--- a/calendar/amd/build/repository.min.js
+++ b/calendar/amd/build/repository.min.js
@@ -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.\n\n/**\n * A javascript module to handle calendar ajax actions.\n *\n * @module core_calendar/repository\n * @class repository\n * @package core_calendar\n * @copyright 2017 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/ajax'], function($, Ajax) {\n\n /**\n * Delete a calendar event.\n *\n * @method deleteEvent\n * @param {int} eventId The event id.\n * @param {bool} deleteSeries Whether to delete all events in the series\n * @return {promise} Resolved with requested calendar event\n */\n var deleteEvent = function(eventId, deleteSeries) {\n if (typeof deleteSeries === 'undefined') {\n deleteSeries = false;\n }\n var request = {\n methodname: 'core_calendar_delete_calendar_events',\n args: {\n events: [{\n eventid: eventId,\n repeat: deleteSeries,\n }]\n }\n };\n\n return Ajax.call([request])[0];\n };\n\n /**\n * Get a calendar event by id.\n *\n * @method getEventById\n * @param {int} eventId The event id.\n * @return {promise} Resolved with requested calendar event\n */\n var getEventById = function(eventId) {\n\n var request = {\n methodname: 'core_calendar_get_calendar_event_by_id',\n args: {\n eventid: eventId\n }\n };\n\n return Ajax.call([request])[0];\n };\n\n /**\n * Submit the form data for the event form.\n *\n * @method submitCreateUpdateForm\n * @param {string} formdata The URL encoded values from the form\n * @return {promise} Resolved with the new or edited event\n */\n var submitCreateUpdateForm = function(formdata) {\n var request = {\n methodname: 'core_calendar_submit_create_update_form',\n args: {\n formdata: formdata\n }\n };\n\n return Ajax.call([request])[0];\n };\n\n /**\n * Get calendar data for the month view.\n *\n * @method getCalendarMonthData\n * @param {Number} year Year\n * @param {Number} month Month\n * @param {Number} courseid The course id.\n * @param {Number} categoryid The category id.\n * @param {Bool} includenavigation Whether to include navigation.\n * @param {Bool} mini Whether the month is in mini view.\n * @return {promise} Resolved with the month view data.\n */\n var getCalendarMonthData = function(year, month, courseid, categoryid, includenavigation, mini) {\n var request = {\n methodname: 'core_calendar_get_calendar_monthly_view',\n args: {\n year: year,\n month: month,\n courseid: courseid,\n categoryid: categoryid,\n includenavigation: includenavigation,\n mini: mini\n }\n };\n\n return Ajax.call([request])[0];\n };\n\n /**\n * Get calendar data for the day view.\n *\n * @method getCalendarDayData\n * @param {Number} year Year\n * @param {Number} month Month\n * @param {Number} day Day\n * @param {Number} courseid The course id.\n * @param {Number} categoryId The id of the category whose events are shown\n * @return {promise} Resolved with the day view data.\n */\n var getCalendarDayData = function(year, month, day, courseid, categoryId) {\n var request = {\n methodname: 'core_calendar_get_calendar_day_view',\n args: {\n year: year,\n month: month,\n day: day,\n courseid: courseid,\n categoryid: categoryId,\n }\n };\n\n return Ajax.call([request])[0];\n };\n\n /**\n * Change the start day for the given event id. The day timestamp\n * only has to be any time during the target day because only the\n * date information is extracted, the time of the day is ignored.\n *\n * @param {int} eventId The id of the event to update\n * @param {int} dayTimestamp A timestamp for some time during the target day\n * @return {promise}\n */\n var updateEventStartDay = function(eventId, dayTimestamp) {\n var request = {\n methodname: 'core_calendar_update_event_start_day',\n args: {\n eventid: eventId,\n daytimestamp: dayTimestamp\n }\n };\n\n return Ajax.call([request])[0];\n };\n\n /**\n * Get calendar upcoming data.\n *\n * @method getCalendarUpcomingData\n * @param {Number} courseid The course id.\n * @param {Number} categoryid The category id.\n * @return {promise} Resolved with the month view data.\n */\n var getCalendarUpcomingData = function(courseid, categoryid) {\n var request = {\n methodname: 'core_calendar_get_calendar_upcoming_view',\n args: {\n courseid: courseid,\n categoryid: categoryid,\n }\n };\n\n return Ajax.call([request])[0];\n };\n\n /**\n * Get the groups by course id.\n *\n * @param {Number} courseid The course id to fetch the groups from.\n * @return {promise} Resolved with the course groups.\n */\n var getCourseGroupsData = function(courseid) {\n var request = {\n methodname: 'core_group_get_course_groups',\n args: {\n courseid: courseid\n }\n };\n\n return Ajax.call([request])[0];\n };\n\n return {\n getEventById: getEventById,\n deleteEvent: deleteEvent,\n updateEventStartDay: updateEventStartDay,\n submitCreateUpdateForm: submitCreateUpdateForm,\n getCalendarMonthData: getCalendarMonthData,\n getCalendarDayData: getCalendarDayData,\n getCalendarUpcomingData: getCalendarUpcomingData,\n getCourseGroupsData: getCourseGroupsData\n };\n});\n"],"file":"repository.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/repository.js"],"names":["deleteEvent","eventId","deleteSeries","Ajax","call","methodname","args","events","eventid","repeat","getEventById","submitCreateUpdateForm","formData","formdata","getCalendarMonthData","year","month","courseId","categoryId","includeNavigation","mini","day","courseid","categoryid","includenavigation","getCalendarDayData","updateEventStartDay","dayTimestamp","daytimestamp","getCalendarUpcomingData","getCourseGroupsData"],"mappings":"sTAwBA,uDAUO,GAAMA,CAAAA,CAAW,CAAG,SAACC,CAAD,CAAmC,IAAzBC,CAAAA,CAAyB,2DAW1D,MAAOC,WAAKC,IAAL,CAAU,CAVD,CACZC,UAAU,CAAE,sCADA,CAEZC,IAAI,CAAE,CACFC,MAAM,CAAE,CAAC,CACLC,OAAO,CAAEP,CADJ,CAELQ,MAAM,CAAEP,CAFH,CAAD,CADN,CAFM,CAUC,CAAV,EAAqB,CAArB,CACV,CAZM,C,gBAqBA,GAAMQ,CAAAA,CAAY,CAAG,SAACT,CAAD,CAAa,CASrC,MAAOE,WAAKC,IAAL,CAAU,CAPD,CACZC,UAAU,CAAE,wCADA,CAEZC,IAAI,CAAE,CACFE,OAAO,CAAEP,CADP,CAFM,CAOC,CAAV,EAAqB,CAArB,CACV,CAVM,C,iBAmBA,GAAMU,CAAAA,CAAsB,CAAG,SAACC,CAAD,CAAc,CAQhD,MAAOT,WAAKC,IAAL,CAAU,CAPD,CACZC,UAAU,CAAE,yCADA,CAEZC,IAAI,CAAE,CACFO,QAAQ,CAAED,CADR,CAFM,CAOC,CAAV,EAAqB,CAArB,CACV,CATM,C,2BAwBA,GAAME,CAAAA,CAAoB,CAAG,SAACC,CAAD,CAAOC,CAAP,CAAcC,CAAd,CAAwBC,CAAxB,CAAoCC,CAApC,CAAuDC,CAAvD,CAAyE,IAAZC,CAAAA,CAAY,wDAAN,CAAM,CAczG,MAAOlB,WAAKC,IAAL,CAAU,CAbD,CACZC,UAAU,CAAE,yCADA,CAEZC,IAAI,CAAE,CACFS,IAAI,CAAJA,CADE,CAEFC,KAAK,CAALA,CAFE,CAGFM,QAAQ,CAAEL,CAHR,CAIFM,UAAU,CAAEL,CAJV,CAKFM,iBAAiB,CAAEL,CALjB,CAMFC,IAAI,CAAJA,CANE,CAOFC,GAAG,CAAHA,CAPE,CAFM,CAaC,CAAV,EAAqB,CAArB,CACV,CAfM,C,yBA4BA,GAAMI,CAAAA,CAAkB,CAAG,SAACV,CAAD,CAAOC,CAAP,CAAcK,CAAd,CAAmBJ,CAAnB,CAA6BC,CAA7B,CAA4C,CAY1E,MAAOf,WAAKC,IAAL,CAAU,CAXD,CACZC,UAAU,CAAE,qCADA,CAEZC,IAAI,CAAE,CACFS,IAAI,CAAJA,CADE,CAEFC,KAAK,CAALA,CAFE,CAGFK,GAAG,CAAHA,CAHE,CAIFC,QAAQ,CAAEL,CAJR,CAKFM,UAAU,CAAEL,CALV,CAFM,CAWC,CAAV,EAAqB,CAArB,CACV,CAbM,C,uBAwBA,GAAMQ,CAAAA,CAAmB,CAAG,SAACzB,CAAD,CAAU0B,CAAV,CAA2B,CAS1D,MAAOxB,WAAKC,IAAL,CAAU,CARD,CACZC,UAAU,CAAE,sCADA,CAEZC,IAAI,CAAE,CACFE,OAAO,CAAEP,CADP,CAEF2B,YAAY,CAAED,CAFZ,CAFM,CAQC,CAAV,EAAqB,CAArB,CACV,CAVM,C,wBAoBA,GAAME,CAAAA,CAAuB,CAAG,SAACZ,CAAD,CAAWC,CAAX,CAA0B,CAS7D,MAAOf,WAAKC,IAAL,CAAU,CARD,CACZC,UAAU,CAAE,0CADA,CAEZC,IAAI,CAAE,CACFgB,QAAQ,CAAEL,CADR,CAEFM,UAAU,CAAEL,CAFV,CAFM,CAQC,CAAV,EAAqB,CAArB,CACV,CAVM,C,4BAkBA,GAAMY,CAAAA,CAAmB,CAAG,SAACb,CAAD,CAAc,CAQ7C,MAAOd,WAAKC,IAAL,CAAU,CAPD,CACZC,UAAU,CAAE,8BADA,CAEZC,IAAI,CAAE,CACFgB,QAAQ,CAAEL,CADR,CAFM,CAOC,CAAV,EAAqB,CAArB,CACV,CATM,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A javascript module to handle calendar ajax actions.\n *\n * @module core_calendar/repository\n * @class repository\n * @package core_calendar\n * @copyright 2017 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport Ajax from 'core/ajax';\n\n/**\n * Delete a calendar event.\n *\n * @method deleteEvent\n * @param {number} eventId The event id.\n * @param {boolean} deleteSeries Whether to delete all events in the series\n * @return {promise} Resolved with requested calendar event\n */\nexport const deleteEvent = (eventId, deleteSeries = false) => {\n const request = {\n methodname: 'core_calendar_delete_calendar_events',\n args: {\n events: [{\n eventid: eventId,\n repeat: deleteSeries,\n }]\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Get a calendar event by id.\n *\n * @method getEventById\n * @param {number} eventId The event id.\n * @return {promise} Resolved with requested calendar event\n */\nexport const getEventById = (eventId) => {\n\n const request = {\n methodname: 'core_calendar_get_calendar_event_by_id',\n args: {\n eventid: eventId\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Submit the form data for the event form.\n *\n * @method submitCreateUpdateForm\n * @param {string} formData The URL encoded values from the form\n * @return {promise} Resolved with the new or edited event\n */\nexport const submitCreateUpdateForm = (formData) => {\n const request = {\n methodname: 'core_calendar_submit_create_update_form',\n args: {\n formdata: formData\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Get calendar data for the month view.\n *\n * @method getCalendarMonthData\n * @param {number} year Year\n * @param {number} month Month\n * @param {number} courseId The course id.\n * @param {number} categoryId The category id.\n * @param {boolean} includeNavigation Whether to include navigation.\n * @param {boolean} mini Whether the month is in mini view.\n * @param {number} day Day (optional)\n * @return {promise} Resolved with the month view data.\n */\nexport const getCalendarMonthData = (year, month, courseId, categoryId, includeNavigation, mini, day = 1) => {\n const request = {\n methodname: 'core_calendar_get_calendar_monthly_view',\n args: {\n year,\n month,\n courseid: courseId,\n categoryid: categoryId,\n includenavigation: includeNavigation,\n mini,\n day,\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Get calendar data for the day view.\n *\n * @method getCalendarDayData\n * @param {number} year Year\n * @param {number} month Month\n * @param {number} day Day\n * @param {number} courseId The course id.\n * @param {number} categoryId The id of the category whose events are shown\n * @return {promise} Resolved with the day view data.\n */\nexport const getCalendarDayData = (year, month, day, courseId, categoryId) => {\n const request = {\n methodname: 'core_calendar_get_calendar_day_view',\n args: {\n year,\n month,\n day,\n courseid: courseId,\n categoryid: categoryId,\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Change the start day for the given event id. The day timestamp\n * only has to be any time during the target day because only the\n * date information is extracted, the time of the day is ignored.\n *\n * @param {int} eventId The id of the event to update\n * @param {int} dayTimestamp A timestamp for some time during the target day\n * @return {promise}\n */\nexport const updateEventStartDay = (eventId, dayTimestamp) => {\n const request = {\n methodname: 'core_calendar_update_event_start_day',\n args: {\n eventid: eventId,\n daytimestamp: dayTimestamp\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Get calendar upcoming data.\n *\n * @method getCalendarUpcomingData\n * @param {number} courseId The course id.\n * @param {number} categoryId The category id.\n * @return {promise} Resolved with the month view data.\n */\nexport const getCalendarUpcomingData = (courseId, categoryId) => {\n const request = {\n methodname: 'core_calendar_get_calendar_upcoming_view',\n args: {\n courseid: courseId,\n categoryid: categoryId,\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Get the groups by course id.\n *\n * @param {Number} courseId The course id to fetch the groups from.\n * @return {promise} Resolved with the course groups.\n */\nexport const getCourseGroupsData = (courseId) => {\n const request = {\n methodname: 'core_group_get_course_groups',\n args: {\n courseid: courseId\n }\n };\n\n return Ajax.call([request])[0];\n};\n"],"file":"repository.min.js"}
\ No newline at end of file
diff --git a/calendar/amd/build/view_manager.min.js b/calendar/amd/build/view_manager.min.js
index 79f116ce8e8..9ffad4e7c9c 100644
--- a/calendar/amd/build/view_manager.min.js
+++ b/calendar/amd/build/view_manager.min.js
@@ -1,2 +1,2 @@
-define ("core_calendar/view_manager",["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(a,b,c,d,e,f,g,h,i,j,k){var l=function(b){b=a(b);b.on("click",g.links.eventLink,function(b){var c=a(b.target),d=null,e;if(c.is(g.actions.viewEvent)){e=c}else{e=c.closest(g.actions.viewEvent)}if(e.length){d=e.data("eventId")}else{d=c.find(g.actions.viewEvent).data("eventId")}if(d){b.preventDefault();b.stopPropagation();u(d)}});b.on("click",g.links.navLink,function(c){var d=b.find(g.wrapper),e=d.data("view"),f=d.data("courseid"),h=d.data("categoryid"),i=a(c.currentTarget);if("month"===e){n(b,i.attr("href"),i.data("year"),i.data("month"),f,h);c.preventDefault()}else if("day"===e){p(b,i.attr("href"),i.data("year"),i.data("month"),i.data("day"),f,h);c.preventDefault()}});var c=b.find(g.viewSelector);k.define(c,[k.events.activate]);c.on(k.events.activate,function(c){c.preventDefault();var e=a(c.target);if(e.hasClass("active")){return}var f=e.data("view"),g=e.data("year"),h=e.data("month"),i=e.data("day"),j=e.data("courseid"),k=e.data("categoryid");if("month"==f){m(b,g,h,j,k,b,"core_calendar/calendar_month").then(function(){return window.history.pushState({},"","?view=month")}).fail(d.exception)}else if("day"==f){o(b,g,h,i,j,k,b,"core_calendar/calendar_day").then(function(){return window.history.pushState({},"","?view=day")}).fail(d.exception)}else if("upcoming"==f){s(b,j,k,b,"core_calendar/calendar_upcoming").then(function(){return window.history.pushState({},"","?view=upcoming")}).fail(d.exception)}})},m=function(c,h,i,j,k,l,m){q(c);l=l||c.find(g.wrapper);m=m||c.attr("data-template");M.util.js_pending([c.get("id"),h,i,j].join("-"));var n=c.data("includenavigation"),o=c.data("mini");return e.getCalendarMonthData(h,i,j,k,n,o).then(function(a){a.viewingmonth=!0;return b.render(m,a)}).then(function(a,c){return b.replaceNode(l,a,c)}).then(function(){a("body").trigger(f.viewUpdated)}).always(function(){M.util.js_complete([c.get("id"),h,i,j].join("-"));return r(c)}).fail(d.exception)},n=function(b,c,d,e,g,h){return m(b,d,e,g,h).then(function(){if(c.length&&"#"!==c){window.history.pushState({},"",c)}return arguments}).then(function(){a("body").trigger(f.monthChanged,[d,e,g,h]);return arguments})},o=function(c,h,i,j,k,l,m,n){q(c);m=m||c.find(g.wrapper);n=n||c.attr("data-template");M.util.js_pending([c.get("id"),h,i,j,k,l].join("-"));var o=c.data("includenavigation");return e.getCalendarDayData(h,i,j,k,l,o).then(function(a){a.viewingday=!0;return b.render(n,a)}).then(function(a,c){return b.replaceNode(m,a,c)}).then(function(){a("body").trigger(f.viewUpdated)}).always(function(){M.util.js_complete([c.get("id"),h,i,j,k,l].join("-"));return r(c)}).fail(d.exception)},p=function(b,c,d,e,g,h,i){return o(b,d,e,g,h,i).then(function(){if(c.length&&"#"!==c){window.history.pushState({},"",c)}return arguments}).then(function(){a("body").trigger(f.dayChanged,[d,e,h,i]);return arguments})},q=function(a){var b=a.find(g.containers.loadingIcon);b.removeClass("hidden")},r=function(a){var b=a.find(g.containers.loadingIcon);b.addClass("hidden")},s=function(c,h,i,j,k){q(c);j=j||c.find(g.wrapper);k=k||c.attr("data-template");if("undefined"==typeof h){h=c.find(g.wrapper).data("courseid")}if("undefined"==typeof i){i=c.find(g.wrapper).data("categoryid")}return e.getCalendarUpcomingData(h,i).then(function(a){a.viewingupcoming=!0;return b.render(k,a)}).then(function(a,c){return b.replaceNode(j,a,c)}).then(function(){a("body").trigger(f.viewUpdated)}).always(function(){return r(c)}).fail(d.exception)},t=function(a){return"calendar_event_"+a},u=function(a){var c="";e.getEventById(a).then(function(b){if(!b.event){throw new Error("Error encountered while trying to fetch calendar event with ID: "+a)}var d=b.event;c=t(d.normalisedeventtype);return d}).then(function(a){var d={title:a.name,type:j.TYPE,body:b.render("core_calendar/event_summary_body",a),templateContext:{canedit:a.canedit,candelete:a.candelete,headerclasses:c,isactionevent:a.isactionevent,url:a.url}};return h.create(d)}).done(function(a){a.getRoot().on(i.hidden,function(){a.destroy()});a.show()}).fail(d.exception)};return{init:function init(a,b){l(a,b)},reloadCurrentMonth:function reloadCurrentMonth(a,b,c){var d=a.find(g.wrapper).data("year"),e=a.find(g.wrapper).data("month");if("undefined"==typeof b){b=a.find(g.wrapper).data("courseid")}if("undefined"==typeof c){c=a.find(g.wrapper).data("categoryid")}return m(a,d,e,b,c)},changeMonth:n,refreshMonthContent:m,reloadCurrentDay:function reloadCurrentDay(a,b,c){var d=a.find(g.wrapper),e=d.data("year"),f=d.data("month"),h=d.data("day");if(!b){b=a.find(g.wrapper).data("courseid")}if("undefined"==typeof c){c=a.find(g.wrapper).data("categoryid")}return o(a,e,f,h,b,c)},changeDay:p,refreshDayContent:o,reloadCurrentUpcoming:s}});
+define ("core_calendar/view_manager",["exports","jquery","core/templates","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(a,b,c,d,e,f,g,h,i,j,k){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=a.reloadCurrentUpcoming=a.changeDay=a.reloadCurrentDay=a.refreshDayContent=a.reloadCurrentMonth=a.changeMonth=a.refreshMonthContent=void 0;b=m(b);c=m(c);d=m(d);e=l(e);f=m(f);g=l(g);h=m(h);i=m(i);j=m(j);k=m(k);function l(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function m(a){return a&&a.__esModule?a:{default:a}}var n=function(a){a=(0,b.default)(a);a.on("click",g.links.eventLink,function(a){var b=a.target,c=null,d=null;if(b.matches(g.actions.viewEvent)){c=b}else{c=b.closest(g.actions.viewEvent)}if(c){d=c.dataset.eventId}else{d=b.querySelector(g.actions.viewEvent).dataset.eventId}if(d){a.preventDefault();a.stopPropagation();y(d)}});a.on("click",g.links.navLink,function(b){var c=a.find(g.wrapper),d=c.data("view"),e=c.data("courseid"),f=c.data("categoryid"),h=b.currentTarget;if("month"===d){p(a,h.href,h.dataset.year,h.dataset.month,e,f,h.dataset.day);b.preventDefault()}else if("day"===d){t(a,h.href,h.dataset.year,h.dataset.month,h.dataset.day,e,f);b.preventDefault()}});var c=a.find(g.viewSelector);k.default.define(c,[k.default.events.activate]);c.on(k.default.events.activate,function(b){b.preventDefault();var c=b.target;if(c.classList.contains("active")){return}var e=c.dataset.view,f=c.dataset.year,g=c.dataset.month,h=c.dataset.day,i=c.dataset.courseid,j=c.dataset.categoryid;if("month"==e){o(a,f,g,i,j,a,"core_calendar/calendar_month",h).then(function(){return window.history.pushState({},"","?view=month")}).fail(d.default.exception)}else if("day"==e){r(a,f,g,h,i,j,a,"core_calendar/calendar_day").then(function(){return window.history.pushState({},"","?view=day")}).fail(d.default.exception)}else if("upcoming"==e){w(a,i,j,a,"core_calendar/calendar_upcoming").then(function(){return window.history.pushState({},"","?view=upcoming")}).fail(d.default.exception)}})},o=function(a,b,h,i,j){var k=5.\n\n/**\n * A javascript module to handler calendar view changes.\n *\n * @module core_calendar/view_manager\n * @package core_calendar\n * @copyright 2017 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/str',\n 'core/notification',\n 'core_calendar/repository',\n 'core_calendar/events',\n 'core_calendar/selectors',\n 'core/modal_factory',\n 'core/modal_events',\n 'core_calendar/summary_modal',\n 'core/custom_interaction_events',\n], function(\n $,\n Templates,\n Str,\n Notification,\n CalendarRepository,\n CalendarEvents,\n CalendarSelectors,\n ModalFactory,\n ModalEvents,\n SummaryModal,\n CustomEvents\n) {\n\n /**\n * Register event listeners for the module.\n *\n * @param {object} root The root element.\n */\n var registerEventListeners = function(root) {\n root = $(root);\n\n // Bind click events to event links.\n root.on('click', CalendarSelectors.links.eventLink, function(e) {\n var target = $(e.target);\n var eventId = null;\n\n var eventLink;\n if (target.is(CalendarSelectors.actions.viewEvent)) {\n eventLink = target;\n } else {\n eventLink = target.closest(CalendarSelectors.actions.viewEvent);\n }\n\n if (eventLink.length) {\n eventId = eventLink.data('eventId');\n } else {\n eventId = target.find(CalendarSelectors.actions.viewEvent).data('eventId');\n }\n\n if (eventId) {\n // A link was found. Show the modal.\n\n e.preventDefault();\n // We've handled the event so stop it from bubbling\n // and causing the day click handler to fire.\n e.stopPropagation();\n\n renderEventSummaryModal(eventId);\n }\n });\n\n\n root.on('click', CalendarSelectors.links.navLink, function(e) {\n var wrapper = root.find(CalendarSelectors.wrapper);\n var view = wrapper.data('view');\n var courseId = wrapper.data('courseid');\n var categoryId = wrapper.data('categoryid');\n var link = $(e.currentTarget);\n\n if (view === 'month') {\n changeMonth(root, link.attr('href'), link.data('year'), link.data('month'), courseId, categoryId);\n e.preventDefault();\n } else if (view === 'day') {\n changeDay(root, link.attr('href'), link.data('year'), link.data('month'), link.data('day'),\n courseId, categoryId);\n e.preventDefault();\n }\n\n });\n\n var viewSelector = root.find(CalendarSelectors.viewSelector);\n CustomEvents.define(viewSelector, [CustomEvents.events.activate]);\n viewSelector.on(\n CustomEvents.events.activate,\n function(e) {\n e.preventDefault();\n\n var option = $(e.target);\n if (option.hasClass('active')) {\n return;\n }\n\n var view = option.data('view'),\n year = option.data('year'),\n month = option.data('month'),\n day = option.data('day'),\n courseId = option.data('courseid'),\n categoryId = option.data('categoryid');\n\n if (view == 'month') {\n refreshMonthContent(root, year, month, courseId, categoryId, root, 'core_calendar/calendar_month')\n .then(function() {\n return window.history.pushState({}, '', '?view=month');\n }).fail(Notification.exception);\n } else if (view == 'day') {\n refreshDayContent(root, year, month, day, courseId, categoryId, root, 'core_calendar/calendar_day')\n .then(function() {\n return window.history.pushState({}, '', '?view=day');\n }).fail(Notification.exception);\n } else if (view == 'upcoming') {\n reloadCurrentUpcoming(root, courseId, categoryId, root, 'core_calendar/calendar_upcoming')\n .then(function() {\n return window.history.pushState({}, '', '?view=upcoming');\n }).fail(Notification.exception);\n }\n }\n );\n };\n\n /**\n * Refresh the month content.\n *\n * @param {object} root The root element.\n * @param {Number} year Year\n * @param {Number} month Month\n * @param {Number} courseid The id of the course whose events are shown\n * @param {Number} categoryid The id of the category whose events are shown\n * @param {object} target The element being replaced. If not specified, the calendarwrapper is used.\n * @param {String} template The template to be rendered.\n * @return {promise}\n */\n var refreshMonthContent = function(root, year, month, courseid, categoryid, target, template) {\n startLoading(root);\n\n target = target || root.find(CalendarSelectors.wrapper);\n template = template || root.attr('data-template');\n M.util.js_pending([root.get('id'), year, month, courseid].join('-'));\n var includenavigation = root.data('includenavigation');\n var mini = root.data('mini');\n return CalendarRepository.getCalendarMonthData(year, month, courseid, categoryid, includenavigation, mini)\n .then(function(context) {\n context.viewingmonth = true;\n return Templates.render(template, context);\n })\n .then(function(html, js) {\n return Templates.replaceNode(target, html, js);\n })\n .then(function() {\n $('body').trigger(CalendarEvents.viewUpdated);\n return;\n })\n .always(function() {\n M.util.js_complete([root.get('id'), year, month, courseid].join('-'));\n return stopLoading(root);\n })\n .fail(Notification.exception);\n };\n\n /**\n * Handle changes to the current calendar view.\n *\n * @param {object} root The container element\n * @param {String} url The calendar url to be shown\n * @param {Number} year Year\n * @param {Number} month Month\n * @param {Number} courseid The id of the course whose events are shown\n * @param {Number} categoryid The id of the category whose events are shown\n * @return {promise}\n */\n var changeMonth = function(root, url, year, month, courseid, categoryid) {\n return refreshMonthContent(root, year, month, courseid, categoryid)\n .then(function() {\n if (url.length && url !== '#') {\n window.history.pushState({}, '', url);\n }\n return arguments;\n })\n .then(function() {\n $('body').trigger(CalendarEvents.monthChanged, [year, month, courseid, categoryid]);\n return arguments;\n });\n };\n\n /**\n * Reload the current month view data.\n *\n * @param {object} root The container element.\n * @param {Number} courseId The course id.\n * @param {Number} categoryId The id of the category whose events are shown\n * @return {promise}\n */\n var reloadCurrentMonth = function(root, courseId, categoryId) {\n var year = root.find(CalendarSelectors.wrapper).data('year');\n var month = root.find(CalendarSelectors.wrapper).data('month');\n\n if (typeof courseId === 'undefined') {\n courseId = root.find(CalendarSelectors.wrapper).data('courseid');\n }\n\n if (typeof categoryId === 'undefined') {\n categoryId = root.find(CalendarSelectors.wrapper).data('categoryid');\n }\n\n return refreshMonthContent(root, year, month, courseId, categoryId);\n };\n\n\n /**\n * Refresh the day content.\n *\n * @param {object} root The root element.\n * @param {Number} year Year\n * @param {Number} month Month\n * @param {Number} day Day\n * @param {Number} courseid The id of the course whose events are shown\n * @param {Number} categoryId The id of the category whose events are shown\n * @param {object} target The element being replaced. If not specified, the calendarwrapper is used.\n * @param {String} template The template to be rendered.\n *\n * @return {promise}\n */\n var refreshDayContent = function(root, year, month, day, courseid, categoryId, target, template) {\n startLoading(root);\n\n target = target || root.find(CalendarSelectors.wrapper);\n template = template || root.attr('data-template');\n M.util.js_pending([root.get('id'), year, month, day, courseid, categoryId].join('-'));\n var includenavigation = root.data('includenavigation');\n return CalendarRepository.getCalendarDayData(year, month, day, courseid, categoryId, includenavigation)\n .then(function(context) {\n context.viewingday = true;\n return Templates.render(template, context);\n })\n .then(function(html, js) {\n return Templates.replaceNode(target, html, js);\n })\n .then(function() {\n $('body').trigger(CalendarEvents.viewUpdated);\n return;\n })\n .always(function() {\n M.util.js_complete([root.get('id'), year, month, day, courseid, categoryId].join('-'));\n return stopLoading(root);\n })\n .fail(Notification.exception);\n };\n\n /**\n * Reload the current day view data.\n *\n * @param {object} root The container element.\n * @param {Number} courseId The course id.\n * @param {Number} categoryId The id of the category whose events are shown\n * @return {promise}\n */\n var reloadCurrentDay = function(root, courseId, categoryId) {\n var wrapper = root.find(CalendarSelectors.wrapper);\n var year = wrapper.data('year');\n var month = wrapper.data('month');\n var day = wrapper.data('day');\n\n if (!courseId) {\n courseId = root.find(CalendarSelectors.wrapper).data('courseid');\n }\n\n if (typeof categoryId === 'undefined') {\n categoryId = root.find(CalendarSelectors.wrapper).data('categoryid');\n }\n\n return refreshDayContent(root, year, month, day, courseId, categoryId);\n };\n\n /**\n * Handle changes to the current calendar view.\n *\n * @param {object} root The root element.\n * @param {String} url The calendar url to be shown\n * @param {Number} year Year\n * @param {Number} month Month\n * @param {Number} day Day\n * @param {Number} courseId The id of the course whose events are shown\n * @param {Number} categoryId The id of the category whose events are shown\n * @return {promise}\n */\n var changeDay = function(root, url, year, month, day, courseId, categoryId) {\n return refreshDayContent(root, year, month, day, courseId, categoryId)\n .then(function() {\n if (url.length && url !== '#') {\n window.history.pushState({}, '', url);\n }\n return arguments;\n })\n .then(function() {\n $('body').trigger(CalendarEvents.dayChanged, [year, month, courseId, categoryId]);\n return arguments;\n });\n };\n\n /**\n * Set the element state to loading.\n *\n * @param {object} root The container element\n * @method startLoading\n */\n var startLoading = function(root) {\n var loadingIconContainer = root.find(CalendarSelectors.containers.loadingIcon);\n\n loadingIconContainer.removeClass('hidden');\n };\n\n /**\n * Remove the loading state from the element.\n *\n * @param {object} root The container element\n * @method stopLoading\n */\n var stopLoading = function(root) {\n var loadingIconContainer = root.find(CalendarSelectors.containers.loadingIcon);\n\n loadingIconContainer.addClass('hidden');\n };\n\n /**\n * Reload the current month view data.\n *\n * @param {object} root The container element.\n * @param {Number} courseId The course id.\n * @param {Number} categoryId The id of the category whose events are shown\n * @param {String} template The template to be rendered.\n * @param {object} target The element being replaced. If not specified, the calendarwrapper is used.\n * @return {promise}\n */\n var reloadCurrentUpcoming = function(root, courseId, categoryId, target, template) {\n startLoading(root);\n\n target = target || root.find(CalendarSelectors.wrapper);\n template = template || root.attr('data-template');\n\n if (typeof courseId === 'undefined') {\n courseId = root.find(CalendarSelectors.wrapper).data('courseid');\n }\n\n if (typeof categoryId === 'undefined') {\n categoryId = root.find(CalendarSelectors.wrapper).data('categoryid');\n }\n\n return CalendarRepository.getCalendarUpcomingData(courseId, categoryId)\n .then(function(context) {\n context.viewingupcoming = true;\n return Templates.render(template, context);\n })\n .then(function(html, js) {\n return Templates.replaceNode(target, html, js);\n })\n .then(function() {\n $('body').trigger(CalendarEvents.viewUpdated);\n return;\n })\n .always(function() {\n return stopLoading(root);\n })\n .fail(Notification.exception);\n };\n\n /**\n * Get the CSS class to apply for the given event type.\n *\n * @param {String} eventType The calendar event type\n * @return {String}\n */\n var getEventTypeClassFromType = function(eventType) {\n return 'calendar_event_' + eventType;\n };\n\n /**\n * Render the event summary modal.\n *\n * @param {Number} eventId The calendar event id.\n */\n var renderEventSummaryModal = function(eventId) {\n var typeClass = '';\n\n // Calendar repository promise.\n CalendarRepository.getEventById(eventId).then(function(getEventResponse) {\n if (!getEventResponse.event) {\n throw new Error('Error encountered while trying to fetch calendar event with ID: ' + eventId);\n }\n var eventData = getEventResponse.event;\n typeClass = getEventTypeClassFromType(eventData.normalisedeventtype);\n\n return eventData;\n }).then(function(eventData) {\n // Build the modal parameters from the event data.\n var modalParams = {\n title: eventData.name,\n type: SummaryModal.TYPE,\n body: Templates.render('core_calendar/event_summary_body', eventData),\n templateContext: {\n canedit: eventData.canedit,\n candelete: eventData.candelete,\n headerclasses: typeClass,\n isactionevent: eventData.isactionevent,\n url: eventData.url\n }\n };\n\n // Create the modal.\n return ModalFactory.create(modalParams);\n\n }).done(function(modal) {\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, function() {\n // Destroy when hidden.\n modal.destroy();\n });\n\n // Finally, render the modal!\n modal.show();\n\n }).fail(Notification.exception);\n };\n\n return {\n init: function(root, view) {\n registerEventListeners(root, view);\n },\n reloadCurrentMonth: reloadCurrentMonth,\n changeMonth: changeMonth,\n refreshMonthContent: refreshMonthContent,\n reloadCurrentDay: reloadCurrentDay,\n changeDay: changeDay,\n refreshDayContent: refreshDayContent,\n reloadCurrentUpcoming: reloadCurrentUpcoming\n };\n });\n"],"file":"view_manager.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/view_manager.js"],"names":["registerEventListeners","root","on","CalendarSelectors","links","eventLink","e","target","eventId","matches","actions","viewEvent","closest","dataset","querySelector","preventDefault","stopPropagation","renderEventSummaryModal","navLink","wrapper","find","view","data","courseId","categoryId","link","currentTarget","changeMonth","href","year","month","day","changeDay","viewSelector","CustomEvents","define","events","activate","option","classList","contains","courseid","categoryid","refreshMonthContent","then","window","history","pushState","fail","Notification","exception","refreshDayContent","reloadCurrentUpcoming","template","startLoading","attr","M","util","js_pending","get","join","includenavigation","mini","CalendarRepository","getCalendarMonthData","context","viewingmonth","Templates","render","html","js","replaceNode","document","dispatchEvent","Event","CalendarEvents","viewUpdated","always","js_complete","stopLoading","url","length","args","trigger","monthChanged","reloadCurrentMonth","getCalendarDayData","viewingday","reloadCurrentDay","dayChanged","loadingIconContainer","containers","loadingIcon","removeClass","addClass","getCalendarUpcomingData","viewingupcoming","getEventTypeClassFromType","eventType","typeClass","getEventById","getEventResponse","event","Error","eventData","normalisedeventtype","modalParams","title","name","type","SummaryModal","TYPE","body","templateContext","canedit","candelete","headerclasses","isactionevent","ModalFactory","create","done","modal","getRoot","ModalEvents","hidden","destroy","show","init"],"mappings":"mgBAwBA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,O,oXAOMA,CAAAA,CAAsB,CAAG,SAACC,CAAD,CAAU,CACrCA,CAAI,CAAG,cAAEA,CAAF,CAAP,CAGAA,CAAI,CAACC,EAAL,CAAQ,OAAR,CAAiBC,CAAiB,CAACC,KAAlB,CAAwBC,SAAzC,CAAoD,SAACC,CAAD,CAAO,IACjDC,CAAAA,CAAM,CAAGD,CAAC,CAACC,MADsC,CAEnDF,CAAS,CAAG,IAFuC,CAGnDG,CAAO,CAAG,IAHyC,CAKvD,GAAID,CAAM,CAACE,OAAP,CAAeN,CAAiB,CAACO,OAAlB,CAA0BC,SAAzC,CAAJ,CAAyD,CACrDN,CAAS,CAAGE,CACf,CAFD,IAEO,CACHF,CAAS,CAAGE,CAAM,CAACK,OAAP,CAAeT,CAAiB,CAACO,OAAlB,CAA0BC,SAAzC,CACf,CAED,GAAIN,CAAJ,CAAe,CACXG,CAAO,CAAGH,CAAS,CAACQ,OAAV,CAAkBL,OAC/B,CAFD,IAEO,CACHA,CAAO,CAAGD,CAAM,CAACO,aAAP,CAAqBX,CAAiB,CAACO,OAAlB,CAA0BC,SAA/C,EAA0DE,OAA1D,CAAkEL,OAC/E,CAED,GAAIA,CAAJ,CAAa,CAGTF,CAAC,CAACS,cAAF,GAGAT,CAAC,CAACU,eAAF,GAEAC,CAAuB,CAACT,CAAD,CAC1B,CACJ,CA3BD,EA6BAP,CAAI,CAACC,EAAL,CAAQ,OAAR,CAAiBC,CAAiB,CAACC,KAAlB,CAAwBc,OAAzC,CAAkD,SAACZ,CAAD,CAAO,IAC/Ca,CAAAA,CAAO,CAAGlB,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,CADqC,CAE/CE,CAAI,CAAGF,CAAO,CAACG,IAAR,CAAa,MAAb,CAFwC,CAG/CC,CAAQ,CAAGJ,CAAO,CAACG,IAAR,CAAa,UAAb,CAHoC,CAI/CE,CAAU,CAAGL,CAAO,CAACG,IAAR,CAAa,YAAb,CAJkC,CAK/CG,CAAI,CAAGnB,CAAC,CAACoB,aALsC,CAOrD,GAAa,OAAT,GAAAL,CAAJ,CAAsB,CAClBM,CAAW,CAAC1B,CAAD,CAAOwB,CAAI,CAACG,IAAZ,CAAkBH,CAAI,CAACZ,OAAL,CAAagB,IAA/B,CAAqCJ,CAAI,CAACZ,OAAL,CAAaiB,KAAlD,CAAyDP,CAAzD,CAAmEC,CAAnE,CAA+EC,CAAI,CAACZ,OAAL,CAAakB,GAA5F,CAAX,CACAzB,CAAC,CAACS,cAAF,EACH,CAHD,IAGO,IAAa,KAAT,GAAAM,CAAJ,CAAoB,CACvBW,CAAS,CAAC/B,CAAD,CAAOwB,CAAI,CAACG,IAAZ,CAAkBH,CAAI,CAACZ,OAAL,CAAagB,IAA/B,CAAqCJ,CAAI,CAACZ,OAAL,CAAaiB,KAAlD,CAAyDL,CAAI,CAACZ,OAAL,CAAakB,GAAtE,CAA2ER,CAA3E,CAAqFC,CAArF,CAAT,CACAlB,CAAC,CAACS,cAAF,EACH,CACJ,CAdD,EAgBA,GAAMkB,CAAAA,CAAY,CAAGhC,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAAC8B,YAA5B,CAArB,CACAC,UAAaC,MAAb,CAAoBF,CAApB,CAAkC,CAACC,UAAaE,MAAb,CAAoBC,QAArB,CAAlC,EACAJ,CAAY,CAAC/B,EAAb,CACIgC,UAAaE,MAAb,CAAoBC,QADxB,CAEI,SAAC/B,CAAD,CAAO,CACHA,CAAC,CAACS,cAAF,GAEA,GAAMuB,CAAAA,CAAM,CAAGhC,CAAC,CAACC,MAAjB,CACA,GAAI+B,CAAM,CAACC,SAAP,CAAiBC,QAAjB,CAA0B,QAA1B,CAAJ,CAAyC,CACrC,MACH,CAED,GAAMnB,CAAAA,CAAI,CAAGiB,CAAM,CAACzB,OAAP,CAAeQ,IAA5B,CACIQ,CAAI,CAAGS,CAAM,CAACzB,OAAP,CAAegB,IAD1B,CAEIC,CAAK,CAAGQ,CAAM,CAACzB,OAAP,CAAeiB,KAF3B,CAGIC,CAAG,CAAGO,CAAM,CAACzB,OAAP,CAAekB,GAHzB,CAIIR,CAAQ,CAAGe,CAAM,CAACzB,OAAP,CAAe4B,QAJ9B,CAKIjB,CAAU,CAAGc,CAAM,CAACzB,OAAP,CAAe6B,UALhC,CAOA,GAAY,OAAR,EAAArB,CAAJ,CAAqB,CACjBsB,CAAmB,CAAC1C,CAAD,CAAO4B,CAAP,CAAaC,CAAb,CAAoBP,CAApB,CAA8BC,CAA9B,CAA0CvB,CAA1C,CAAgD,8BAAhD,CAAgF8B,CAAhF,CAAnB,CACKa,IADL,CACU,UAAM,CACR,MAAOC,CAAAA,MAAM,CAACC,OAAP,CAAeC,SAAf,CAAyB,EAAzB,CAA6B,EAA7B,CAAiC,aAAjC,CACV,CAHL,EAGOC,IAHP,CAGYC,UAAaC,SAHzB,CAIH,CALD,IAKO,IAAY,KAAR,EAAA7B,CAAJ,CAAmB,CACtB8B,CAAiB,CAAClD,CAAD,CAAO4B,CAAP,CAAaC,CAAb,CAAoBC,CAApB,CAAyBR,CAAzB,CAAmCC,CAAnC,CAA+CvB,CAA/C,CAAqD,4BAArD,CAAjB,CACK2C,IADL,CACU,UAAM,CACR,MAAOC,CAAAA,MAAM,CAACC,OAAP,CAAeC,SAAf,CAAyB,EAAzB,CAA6B,EAA7B,CAAiC,WAAjC,CACV,CAHL,EAGOC,IAHP,CAGYC,UAAaC,SAHzB,CAIH,CALM,IAKA,IAAY,UAAR,EAAA7B,CAAJ,CAAwB,CAC3B+B,CAAqB,CAACnD,CAAD,CAAOsB,CAAP,CAAiBC,CAAjB,CAA6BvB,CAA7B,CAAmC,iCAAnC,CAArB,CACK2C,IADL,CACU,UAAM,CACR,MAAOC,CAAAA,MAAM,CAACC,OAAP,CAAeC,SAAf,CAAyB,EAAzB,CAA6B,EAA7B,CAAiC,gBAAjC,CACV,CAHL,EAGOC,IAHP,CAGYC,UAAaC,SAHzB,CAIH,CACJ,CAjCL,CAmCH,C,CAeYP,CAAmB,CAAG,SAAC1C,CAAD,CAAO4B,CAAP,CAAaC,CAAb,CAAoBP,CAApB,CAA8BC,CAA9B,CAAoF,IAA1CjB,CAAAA,CAA0C,wDAAjC,IAAiC,CAA3B8C,CAA2B,wDAAhB,EAAgB,CAAZtB,CAAY,wDAAN,CAAM,CACnHuB,CAAY,CAACrD,CAAD,CAAZ,CAEAM,CAAM,CAAGA,CAAM,EAAIN,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,CAAnB,CACAkC,CAAQ,CAAGA,CAAQ,EAAIpD,CAAI,CAACsD,IAAL,CAAU,eAAV,CAAvB,CACAC,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkB,CAACzD,CAAI,CAAC0D,GAAL,CAAS,IAAT,CAAD,CAAiB9B,CAAjB,CAAuBC,CAAvB,CAA8BP,CAA9B,EAAwCqC,IAAxC,CAA6C,GAA7C,CAAlB,EALmH,GAM7GC,CAAAA,CAAiB,CAAG5D,CAAI,CAACqB,IAAL,CAAU,mBAAV,CANyF,CAO7GwC,CAAI,CAAG7D,CAAI,CAACqB,IAAL,CAAU,MAAV,CAPsG,CAQnH,MAAOyC,CAAAA,CAAkB,CAACC,oBAAnB,CAAwCnC,CAAxC,CAA8CC,CAA9C,CAAqDP,CAArD,CAA+DC,CAA/D,CAA2EqC,CAA3E,CAA8FC,CAA9F,CAAoG/B,CAApG,EACFa,IADE,CACG,SAAAqB,CAAO,CAAI,CACbA,CAAO,CAACC,YAAR,IACA,MAAOC,WAAUC,MAAV,CAAiBf,CAAjB,CAA2BY,CAA3B,CACV,CAJE,EAKFrB,IALE,CAKG,SAACyB,CAAD,CAAOC,CAAP,CAAc,CAChB,MAAOH,WAAUI,WAAV,CAAsBhE,CAAtB,CAA8B8D,CAA9B,CAAoCC,CAApC,CACV,CAPE,EAQF1B,IARE,CAQG,UAAM,CACR4B,QAAQ,CAAC1D,aAAT,CAAuB,MAAvB,EAA+B2D,aAA/B,CAA6C,GAAIC,CAAAA,KAAJ,CAAUC,UAAeC,WAAzB,CAA7C,CAEH,CAXE,EAYFC,MAZE,CAYK,UAAM,CACVrB,CAAC,CAACC,IAAF,CAAOqB,WAAP,CAAmB,CAAC7E,CAAI,CAAC0D,GAAL,CAAS,IAAT,CAAD,CAAiB9B,CAAjB,CAAuBC,CAAvB,CAA8BP,CAA9B,EAAwCqC,IAAxC,CAA6C,GAA7C,CAAnB,EACA,MAAOmB,CAAAA,CAAW,CAAC9E,CAAD,CACrB,CAfE,EAgBF+C,IAhBE,CAgBGC,UAAaC,SAhBhB,CAiBV,C,yBAcM,GAAMvB,CAAAA,CAAW,CAAG,SAAC1B,CAAD,CAAO+E,CAAP,CAAYnD,CAAZ,CAAkBC,CAAlB,CAAyBP,CAAzB,CAAmCC,CAAnC,CAA2D,IAAZO,CAAAA,CAAY,wDAAN,CAAM,CAClF,MAAOY,CAAAA,CAAmB,CAAC1C,CAAD,CAAO4B,CAAP,CAAaC,CAAb,CAAoBP,CAApB,CAA8BC,CAA9B,CAA0C,IAA1C,CAAgD,EAAhD,CAAoDO,CAApD,CAAnB,CACFa,IADE,CACG,UAAa,CACf,GAAIoC,CAAG,CAACC,MAAJ,EAAsB,GAAR,GAAAD,CAAlB,CAA+B,CAC3BnC,MAAM,CAACC,OAAP,CAAeC,SAAf,CAAyB,EAAzB,CAA6B,EAA7B,CAAiCiC,CAAjC,CACH,CAHc,2BAATE,CAAS,uBAATA,CAAS,iBAIf,MAAOA,CAAAA,CACV,CANE,EAOFtC,IAPE,CAOG,UAAa,CACf,cAAE,MAAF,EAAUuC,OAAV,CAAkBR,UAAeS,YAAjC,CAA+C,CAACvD,CAAD,CAAOC,CAAP,CAAcP,CAAd,CAAwBC,CAAxB,CAA/C,EADe,2BAAT0D,CAAS,uBAATA,CAAS,iBAEf,MAAOA,CAAAA,CACV,CAVE,CAWV,CAZM,C,gBAsBA,GAAMG,CAAAA,CAAkB,CAAG,SAACpF,CAAD,CAAwC,IAAjCsB,CAAAA,CAAiC,wDAAtB,CAAsB,CAAnBC,CAAmB,wDAAN,CAAM,CAChEK,CAAI,CAAG5B,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,EAAqCG,IAArC,CAA0C,MAA1C,CADyD,CAEhEQ,CAAK,CAAG7B,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,EAAqCG,IAArC,CAA0C,OAA1C,CAFwD,CAGhES,CAAG,CAAG9B,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,EAAqCG,IAArC,CAA0C,KAA1C,CAH0D,CAKtEC,CAAQ,CAAGA,CAAQ,EAAItB,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,EAAqCG,IAArC,CAA0C,UAA1C,CAAvB,CACAE,CAAU,CAAGA,CAAU,EAAIvB,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,EAAqCG,IAArC,CAA0C,YAA1C,CAA3B,CAEA,MAAOqB,CAAAA,CAAmB,CAAC1C,CAAD,CAAO4B,CAAP,CAAaC,CAAb,CAAoBP,CAApB,CAA8BC,CAA9B,CAA0C,IAA1C,CAAgD,EAAhD,CAAoDO,CAApD,CAC7B,CATM,C,uBA0BA,GAAMoB,CAAAA,CAAiB,CAAG,SAAClD,CAAD,CAAO4B,CAAP,CAAaC,CAAb,CAAoBC,CAApB,CAAyBR,CAAzB,CAAmCC,CAAnC,CAAgF,IAAjCjB,CAAAA,CAAiC,wDAAxB,IAAwB,CAAlB8C,CAAkB,wDAAP,EAAO,CAC7GC,CAAY,CAACrD,CAAD,CAAZ,CAEAM,CAAM,CAAGA,CAAM,EAAIN,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,CAAnB,CACAkC,CAAQ,CAAGA,CAAQ,EAAIpD,CAAI,CAACsD,IAAL,CAAU,eAAV,CAAvB,CACAC,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkB,CAACzD,CAAI,CAAC0D,GAAL,CAAS,IAAT,CAAD,CAAiB9B,CAAjB,CAAuBC,CAAvB,CAA8BC,CAA9B,CAAmCR,CAAnC,CAA6CC,CAA7C,EAAyDoC,IAAzD,CAA8D,GAA9D,CAAlB,EACA,GAAMC,CAAAA,CAAiB,CAAG5D,CAAI,CAACqB,IAAL,CAAU,mBAAV,CAA1B,CACA,MAAOyC,CAAAA,CAAkB,CAACuB,kBAAnB,CAAsCzD,CAAtC,CAA4CC,CAA5C,CAAmDC,CAAnD,CAAwDR,CAAxD,CAAkEC,CAAlE,CAA8EqC,CAA9E,EACFjB,IADE,CACG,SAACqB,CAAD,CAAa,CACfA,CAAO,CAACsB,UAAR,IACA,MAAOpB,WAAUC,MAAV,CAAiBf,CAAjB,CAA2BY,CAA3B,CACV,CAJE,EAKFrB,IALE,CAKG,SAACyB,CAAD,CAAOC,CAAP,CAAc,CAChB,MAAOH,WAAUI,WAAV,CAAsBhE,CAAtB,CAA8B8D,CAA9B,CAAoCC,CAApC,CACV,CAPE,EAQF1B,IARE,CAQG,UAAM,CACR4B,QAAQ,CAAC1D,aAAT,CAAuB,MAAvB,EAA+B2D,aAA/B,CAA6C,GAAIC,CAAAA,KAAJ,CAAUC,UAAeC,WAAzB,CAA7C,CAEH,CAXE,EAYFC,MAZE,CAYK,UAAM,CACVrB,CAAC,CAACC,IAAF,CAAOqB,WAAP,CAAmB,CAAC7E,CAAI,CAAC0D,GAAL,CAAS,IAAT,CAAD,CAAiB9B,CAAjB,CAAuBC,CAAvB,CAA8BC,CAA9B,CAAmCR,CAAnC,CAA6CC,CAA7C,EAAyDoC,IAAzD,CAA8D,GAA9D,CAAnB,EACA,MAAOmB,CAAAA,CAAW,CAAC9E,CAAD,CACrB,CAfE,EAgBF+C,IAhBE,CAgBGC,UAAaC,SAhBhB,CAiBV,CAxBM,C,sBAkCA,GAAMsC,CAAAA,CAAgB,CAAG,SAACvF,CAAD,CAAwC,IAAjCsB,CAAAA,CAAiC,wDAAtB,CAAsB,CAAnBC,CAAmB,wDAAN,CAAM,CAC9DL,CAAO,CAAGlB,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,CADoD,CAE9DU,CAAI,CAAGV,CAAO,CAACG,IAAR,CAAa,MAAb,CAFuD,CAG9DQ,CAAK,CAAGX,CAAO,CAACG,IAAR,CAAa,OAAb,CAHsD,CAI9DS,CAAG,CAAGZ,CAAO,CAACG,IAAR,CAAa,KAAb,CAJwD,CAMpEC,CAAQ,CAAGA,CAAQ,EAAItB,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,EAAqCG,IAArC,CAA0C,UAA1C,CAAvB,CACAE,CAAU,CAAGA,CAAU,EAAIvB,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,EAAqCG,IAArC,CAA0C,YAA1C,CAA3B,CAEA,MAAO6B,CAAAA,CAAiB,CAAClD,CAAD,CAAO4B,CAAP,CAAaC,CAAb,CAAoBC,CAApB,CAAyBR,CAAzB,CAAmCC,CAAnC,CAC3B,CAVM,C,qBAwBA,GAAMQ,CAAAA,CAAS,CAAG,SAAC/B,CAAD,CAAO+E,CAAP,CAAYnD,CAAZ,CAAkBC,CAAlB,CAAyBC,CAAzB,CAA8BR,CAA9B,CAAwCC,CAAxC,CAAuD,CAC5E,MAAO2B,CAAAA,CAAiB,CAAClD,CAAD,CAAO4B,CAAP,CAAaC,CAAb,CAAoBC,CAApB,CAAyBR,CAAzB,CAAmCC,CAAnC,CAAjB,CACFoB,IADE,CACG,UAAa,CACf,GAAIoC,CAAG,CAACC,MAAJ,EAAsB,GAAR,GAAAD,CAAlB,CAA+B,CAC3BnC,MAAM,CAACC,OAAP,CAAeC,SAAf,CAAyB,EAAzB,CAA6B,EAA7B,CAAiCiC,CAAjC,CACH,CAHc,2BAATE,CAAS,uBAATA,CAAS,iBAIf,MAAOA,CAAAA,CACV,CANE,EAOFtC,IAPE,CAOG,UAAa,CACf,cAAE,MAAF,EAAUuC,OAAV,CAAkBR,UAAec,UAAjC,CAA6C,CAAC5D,CAAD,CAAOC,CAAP,CAAcP,CAAd,CAAwBC,CAAxB,CAA7C,EADe,2BAAT0D,CAAS,uBAATA,CAAS,iBAEf,MAAOA,CAAAA,CACV,CAVE,CAWV,CAZM,C,iBAoBD5B,CAAAA,CAAY,CAAG,SAACrD,CAAD,CAAU,CAC3B,GAAMyF,CAAAA,CAAoB,CAAGzF,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACwF,UAAlB,CAA6BC,WAAvC,CAA7B,CAEAF,CAAoB,CAACG,WAArB,CAAiC,QAAjC,CACH,C,CAQKd,CAAW,CAAG,SAAC9E,CAAD,CAAU,CAC1B,GAAMyF,CAAAA,CAAoB,CAAGzF,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACwF,UAAlB,CAA6BC,WAAvC,CAA7B,CAEAF,CAAoB,CAACI,QAArB,CAA8B,QAA9B,CACH,C,CAYY1C,CAAqB,CAAG,SAACnD,CAAD,CAAsE,IAA/DsB,CAAAA,CAA+D,wDAApD,CAAoD,CAAjDC,CAAiD,wDAApC,CAAoC,CAAjCjB,CAAiC,wDAAxB,IAAwB,CAAlB8C,CAAkB,wDAAP,EAAO,CACvGC,CAAY,CAACrD,CAAD,CAAZ,CAEAM,CAAM,CAAGA,CAAM,EAAIN,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,CAAnB,CACAkC,CAAQ,CAAGA,CAAQ,EAAIpD,CAAI,CAACsD,IAAL,CAAU,eAAV,CAAvB,CACAhC,CAAQ,CAAGA,CAAQ,EAAItB,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,EAAqCG,IAArC,CAA0C,UAA1C,CAAvB,CACAE,CAAU,CAAGA,CAAU,EAAIvB,CAAI,CAACmB,IAAL,CAAUjB,CAAiB,CAACgB,OAA5B,EAAqCG,IAArC,CAA0C,YAA1C,CAA3B,CAEA,MAAOyC,CAAAA,CAAkB,CAACgC,uBAAnB,CAA2CxE,CAA3C,CAAqDC,CAArD,EACFoB,IADE,CACG,SAACqB,CAAD,CAAa,CACfA,CAAO,CAAC+B,eAAR,IACA,MAAO7B,WAAUC,MAAV,CAAiBf,CAAjB,CAA2BY,CAA3B,CACV,CAJE,EAKFrB,IALE,CAKG,SAACyB,CAAD,CAAOC,CAAP,CAAc,CAChB,MAAOH,WAAUI,WAAV,CAAsBhE,CAAtB,CAA8B8D,CAA9B,CAAoCC,CAApC,CACV,CAPE,EAQF1B,IARE,CAQG,UAAM,CACR4B,QAAQ,CAAC1D,aAAT,CAAuB,MAAvB,EAA+B2D,aAA/B,CAA6C,GAAIC,CAAAA,KAAJ,CAAUC,UAAeC,WAAzB,CAA7C,CAEH,CAXE,EAYFC,MAZE,CAYK,UAAW,CACf,MAAOE,CAAAA,CAAW,CAAC9E,CAAD,CACrB,CAdE,EAeF+C,IAfE,CAeGC,UAAaC,SAfhB,CAgBV,C,8BAQK+C,CAAAA,CAAyB,CAAG,SAACC,CAAD,CAAe,CAC7C,MAAO,kBAAoBA,CAC9B,C,CAOKjF,CAAuB,CAAG,SAACT,CAAD,CAAa,CACzC,GAAI2F,CAAAA,CAAS,CAAG,EAAhB,CAGApC,CAAkB,CAACqC,YAAnB,CAAgC5F,CAAhC,EAAyCoC,IAAzC,CAA8C,SAACyD,CAAD,CAAsB,CAChE,GAAI,CAACA,CAAgB,CAACC,KAAtB,CAA6B,CACzB,KAAM,IAAIC,CAAAA,KAAJ,CAAU,mEAAqE/F,CAA/E,CACT,CACD,GAAMgG,CAAAA,CAAS,CAAGH,CAAgB,CAACC,KAAnC,CACAH,CAAS,CAAGF,CAAyB,CAACO,CAAS,CAACC,mBAAX,CAArC,CAEA,MAAOD,CAAAA,CACV,CARD,EAQG5D,IARH,CAQQ,SAAC4D,CAAD,CAAe,CAEnB,GAAME,CAAAA,CAAW,CAAG,CAChBC,KAAK,CAAEH,CAAS,CAACI,IADD,CAEhBC,IAAI,CAAEC,UAAaC,IAFH,CAGhBC,IAAI,CAAE7C,UAAUC,MAAV,CAAiB,kCAAjB,CAAqDoC,CAArD,CAHU,CAIhBS,eAAe,CAAE,CACbC,OAAO,CAAEV,CAAS,CAACU,OADN,CAEbC,SAAS,CAAEX,CAAS,CAACW,SAFR,CAGbC,aAAa,CAAEjB,CAHF,CAIbkB,aAAa,CAAEb,CAAS,CAACa,aAJZ,CAKbrC,GAAG,CAAEwB,CAAS,CAACxB,GALF,CAJD,CAApB,CAcA,MAAOsC,WAAaC,MAAb,CAAoBb,CAApB,CAEV,CA1BD,EA0BGc,IA1BH,CA0BQ,SAASC,CAAT,CAAgB,CAEpBA,CAAK,CAACC,OAAN,GAAgBxH,EAAhB,CAAmByH,UAAYC,MAA/B,CAAuC,UAAW,CAE9CH,CAAK,CAACI,OAAN,EACH,CAHD,EAMAJ,CAAK,CAACK,IAAN,EAEH,CApCD,EAoCG9E,IApCH,CAoCQC,UAAaC,SApCrB,CAqCH,C,QAEmB,QAAP6E,CAAAA,IAAO,CAAC9H,CAAD,CAAOoB,CAAP,CAAgB,CAChCrB,CAAsB,CAACC,CAAD,CAAOoB,CAAP,CACzB,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A javascript module to handler calendar view changes.\n *\n * @module core_calendar/view_manager\n * @package core_calendar\n * @copyright 2017 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport Templates from 'core/templates';\nimport Notification from 'core/notification';\nimport * as CalendarRepository from 'core_calendar/repository';\nimport CalendarEvents from 'core_calendar/events';\nimport * as CalendarSelectors from 'core_calendar/selectors';\nimport ModalFactory from 'core/modal_factory';\nimport ModalEvents from 'core/modal_events';\nimport SummaryModal from 'core_calendar/summary_modal';\nimport CustomEvents from 'core/custom_interaction_events';\n\n/**\n * Register event listeners for the module.\n *\n * @param {object} root The root element.\n */\nconst registerEventListeners = (root) => {\n root = $(root);\n\n // Bind click events to event links.\n root.on('click', CalendarSelectors.links.eventLink, (e) => {\n const target = e.target;\n let eventLink = null;\n let eventId = null;\n\n if (target.matches(CalendarSelectors.actions.viewEvent)) {\n eventLink = target;\n } else {\n eventLink = target.closest(CalendarSelectors.actions.viewEvent);\n }\n\n if (eventLink) {\n eventId = eventLink.dataset.eventId;\n } else {\n eventId = target.querySelector(CalendarSelectors.actions.viewEvent).dataset.eventId;\n }\n\n if (eventId) {\n // A link was found. Show the modal.\n\n e.preventDefault();\n // We've handled the event so stop it from bubbling\n // and causing the day click handler to fire.\n e.stopPropagation();\n\n renderEventSummaryModal(eventId);\n }\n });\n\n root.on('click', CalendarSelectors.links.navLink, (e) => {\n const wrapper = root.find(CalendarSelectors.wrapper);\n const view = wrapper.data('view');\n const courseId = wrapper.data('courseid');\n const categoryId = wrapper.data('categoryid');\n const link = e.currentTarget;\n\n if (view === 'month') {\n changeMonth(root, link.href, link.dataset.year, link.dataset.month, courseId, categoryId, link.dataset.day);\n e.preventDefault();\n } else if (view === 'day') {\n changeDay(root, link.href, link.dataset.year, link.dataset.month, link.dataset.day, courseId, categoryId);\n e.preventDefault();\n }\n });\n\n const viewSelector = root.find(CalendarSelectors.viewSelector);\n CustomEvents.define(viewSelector, [CustomEvents.events.activate]);\n viewSelector.on(\n CustomEvents.events.activate,\n (e) => {\n e.preventDefault();\n\n const option = e.target;\n if (option.classList.contains('active')) {\n return;\n }\n\n const view = option.dataset.view,\n year = option.dataset.year,\n month = option.dataset.month,\n day = option.dataset.day,\n courseId = option.dataset.courseid,\n categoryId = option.dataset.categoryid;\n\n if (view == 'month') {\n refreshMonthContent(root, year, month, courseId, categoryId, root, 'core_calendar/calendar_month', day)\n .then(() => {\n return window.history.pushState({}, '', '?view=month');\n }).fail(Notification.exception);\n } else if (view == 'day') {\n refreshDayContent(root, year, month, day, courseId, categoryId, root, 'core_calendar/calendar_day')\n .then(() => {\n return window.history.pushState({}, '', '?view=day');\n }).fail(Notification.exception);\n } else if (view == 'upcoming') {\n reloadCurrentUpcoming(root, courseId, categoryId, root, 'core_calendar/calendar_upcoming')\n .then(() => {\n return window.history.pushState({}, '', '?view=upcoming');\n }).fail(Notification.exception);\n }\n }\n );\n};\n\n/**\n * Refresh the month content.\n *\n * @param {object} root The root element.\n * @param {number} year Year\n * @param {number} month Month\n * @param {number} courseId The id of the course whose events are shown\n * @param {number} categoryId The id of the category whose events are shown\n * @param {object} target The element being replaced. If not specified, the calendarwrapper is used.\n * @param {string} template The template to be rendered.\n * @param {number} day Day (optional)\n * @return {promise}\n */\nexport const refreshMonthContent = (root, year, month, courseId, categoryId, target = null, template = '', day = 1) => {\n startLoading(root);\n\n target = target || root.find(CalendarSelectors.wrapper);\n template = template || root.attr('data-template');\n M.util.js_pending([root.get('id'), year, month, courseId].join('-'));\n const includenavigation = root.data('includenavigation');\n const mini = root.data('mini');\n return CalendarRepository.getCalendarMonthData(year, month, courseId, categoryId, includenavigation, mini, day)\n .then(context => {\n context.viewingmonth = true;\n return Templates.render(template, context);\n })\n .then((html, js) => {\n return Templates.replaceNode(target, html, js);\n })\n .then(() => {\n document.querySelector('body').dispatchEvent(new Event(CalendarEvents.viewUpdated));\n return;\n })\n .always(() => {\n M.util.js_complete([root.get('id'), year, month, courseId].join('-'));\n return stopLoading(root);\n })\n .fail(Notification.exception);\n};\n\n/**\n * Handle changes to the current calendar view.\n *\n * @param {object} root The container element\n * @param {string} url The calendar url to be shown\n * @param {number} year Year\n * @param {number} month Month\n * @param {number} courseId The id of the course whose events are shown\n * @param {number} categoryId The id of the category whose events are shown\n * @param {number} day Day (optional)\n * @return {promise}\n */\nexport const changeMonth = (root, url, year, month, courseId, categoryId, day = 1) => {\n return refreshMonthContent(root, year, month, courseId, categoryId, null, '', day)\n .then((...args) => {\n if (url.length && url !== '#') {\n window.history.pushState({}, '', url);\n }\n return args;\n })\n .then((...args) => {\n $('body').trigger(CalendarEvents.monthChanged, [year, month, courseId, categoryId]);\n return args;\n });\n};\n\n/**\n * Reload the current month view data.\n *\n * @param {object} root The container element.\n * @param {number} courseId The course id.\n * @param {number} categoryId The id of the category whose events are shown\n * @return {promise}\n */\nexport const reloadCurrentMonth = (root, courseId = 0, categoryId = 0) => {\n const year = root.find(CalendarSelectors.wrapper).data('year');\n const month = root.find(CalendarSelectors.wrapper).data('month');\n const day = root.find(CalendarSelectors.wrapper).data('day');\n\n courseId = courseId || root.find(CalendarSelectors.wrapper).data('courseid');\n categoryId = categoryId || root.find(CalendarSelectors.wrapper).data('categoryid');\n\n return refreshMonthContent(root, year, month, courseId, categoryId, null, '', day);\n};\n\n\n/**\n * Refresh the day content.\n *\n * @param {object} root The root element.\n * @param {number} year Year\n * @param {number} month Month\n * @param {number} day Day\n * @param {number} courseId The id of the course whose events are shown\n * @param {number} categoryId The id of the category whose events are shown\n * @param {object} target The element being replaced. If not specified, the calendarwrapper is used.\n * @param {string} template The template to be rendered.\n *\n * @return {promise}\n */\nexport const refreshDayContent = (root, year, month, day, courseId, categoryId, target = null, template = '') => {\n startLoading(root);\n\n target = target || root.find(CalendarSelectors.wrapper);\n template = template || root.attr('data-template');\n M.util.js_pending([root.get('id'), year, month, day, courseId, categoryId].join('-'));\n const includenavigation = root.data('includenavigation');\n return CalendarRepository.getCalendarDayData(year, month, day, courseId, categoryId, includenavigation)\n .then((context) => {\n context.viewingday = true;\n return Templates.render(template, context);\n })\n .then((html, js) => {\n return Templates.replaceNode(target, html, js);\n })\n .then(() => {\n document.querySelector('body').dispatchEvent(new Event(CalendarEvents.viewUpdated));\n return;\n })\n .always(() => {\n M.util.js_complete([root.get('id'), year, month, day, courseId, categoryId].join('-'));\n return stopLoading(root);\n })\n .fail(Notification.exception);\n};\n\n/**\n * Reload the current day view data.\n *\n * @param {object} root The container element.\n * @param {number} courseId The course id.\n * @param {number} categoryId The id of the category whose events are shown\n * @return {promise}\n */\nexport const reloadCurrentDay = (root, courseId = 0, categoryId = 0) => {\n const wrapper = root.find(CalendarSelectors.wrapper);\n const year = wrapper.data('year');\n const month = wrapper.data('month');\n const day = wrapper.data('day');\n\n courseId = courseId || root.find(CalendarSelectors.wrapper).data('courseid');\n categoryId = categoryId || root.find(CalendarSelectors.wrapper).data('categoryid');\n\n return refreshDayContent(root, year, month, day, courseId, categoryId);\n};\n\n/**\n * Handle changes to the current calendar view.\n *\n * @param {object} root The root element.\n * @param {String} url The calendar url to be shown\n * @param {Number} year Year\n * @param {Number} month Month\n * @param {Number} day Day\n * @param {Number} courseId The id of the course whose events are shown\n * @param {Number} categoryId The id of the category whose events are shown\n * @return {promise}\n */\nexport const changeDay = (root, url, year, month, day, courseId, categoryId) => {\n return refreshDayContent(root, year, month, day, courseId, categoryId)\n .then((...args) => {\n if (url.length && url !== '#') {\n window.history.pushState({}, '', url);\n }\n return args;\n })\n .then((...args) => {\n $('body').trigger(CalendarEvents.dayChanged, [year, month, courseId, categoryId]);\n return args;\n });\n};\n\n/**\n * Set the element state to loading.\n *\n * @param {object} root The container element\n * @method startLoading\n */\nconst startLoading = (root) => {\n const loadingIconContainer = root.find(CalendarSelectors.containers.loadingIcon);\n\n loadingIconContainer.removeClass('hidden');\n};\n\n/**\n * Remove the loading state from the element.\n *\n * @param {object} root The container element\n * @method stopLoading\n */\nconst stopLoading = (root) => {\n const loadingIconContainer = root.find(CalendarSelectors.containers.loadingIcon);\n\n loadingIconContainer.addClass('hidden');\n};\n\n/**\n * Reload the current month view data.\n *\n * @param {object} root The container element.\n * @param {number} courseId The course id.\n * @param {number} categoryId The id of the category whose events are shown\n * @param {string} template The template to be rendered.\n * @param {object} target The element being replaced. If not specified, the calendarwrapper is used.\n * @return {promise}\n */\nexport const reloadCurrentUpcoming = (root, courseId = 0, categoryId = 0, target = null, template = '') => {\n startLoading(root);\n\n target = target || root.find(CalendarSelectors.wrapper);\n template = template || root.attr('data-template');\n courseId = courseId || root.find(CalendarSelectors.wrapper).data('courseid');\n categoryId = categoryId || root.find(CalendarSelectors.wrapper).data('categoryid');\n\n return CalendarRepository.getCalendarUpcomingData(courseId, categoryId)\n .then((context) => {\n context.viewingupcoming = true;\n return Templates.render(template, context);\n })\n .then((html, js) => {\n return Templates.replaceNode(target, html, js);\n })\n .then(() => {\n document.querySelector('body').dispatchEvent(new Event(CalendarEvents.viewUpdated));\n return;\n })\n .always(function() {\n return stopLoading(root);\n })\n .fail(Notification.exception);\n};\n\n/**\n * Get the CSS class to apply for the given event type.\n *\n * @param {string} eventType The calendar event type\n * @return {string}\n */\nconst getEventTypeClassFromType = (eventType) => {\n return 'calendar_event_' + eventType;\n};\n\n/**\n * Render the event summary modal.\n *\n * @param {Number} eventId The calendar event id.\n */\nconst renderEventSummaryModal = (eventId) => {\n let typeClass = '';\n\n // Calendar repository promise.\n CalendarRepository.getEventById(eventId).then((getEventResponse) => {\n if (!getEventResponse.event) {\n throw new Error('Error encountered while trying to fetch calendar event with ID: ' + eventId);\n }\n const eventData = getEventResponse.event;\n typeClass = getEventTypeClassFromType(eventData.normalisedeventtype);\n\n return eventData;\n }).then((eventData) => {\n // Build the modal parameters from the event data.\n const modalParams = {\n title: eventData.name,\n type: SummaryModal.TYPE,\n body: Templates.render('core_calendar/event_summary_body', eventData),\n templateContext: {\n canedit: eventData.canedit,\n candelete: eventData.candelete,\n headerclasses: typeClass,\n isactionevent: eventData.isactionevent,\n url: eventData.url\n }\n };\n\n // Create the modal.\n return ModalFactory.create(modalParams);\n\n }).done(function(modal) {\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, function() {\n // Destroy when hidden.\n modal.destroy();\n });\n\n // Finally, render the modal!\n modal.show();\n\n }).fail(Notification.exception);\n};\n\nexport const init = (root, view) => {\n registerEventListeners(root, view);\n};\n"],"file":"view_manager.min.js"}
\ No newline at end of file
diff --git a/calendar/amd/src/repository.js b/calendar/amd/src/repository.js
index d8166fae7e4..baa66ca055d 100644
--- a/calendar/amd/src/repository.js
+++ b/calendar/amd/src/repository.js
@@ -22,190 +22,177 @@
* @copyright 2017 Simey Lameze
* @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];
+};
diff --git a/calendar/amd/src/view_manager.js b/calendar/amd/src/view_manager.js
index 887645ba403..add784486fe 100644
--- a/calendar/amd/src/view_manager.js
+++ b/calendar/amd/src/view_manager.js
@@ -21,441 +21,401 @@
* @copyright 2017 Andrew Nicols
* @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);
+};
diff --git a/calendar/externallib.php b/calendar/externallib.php
index d7f83479954..4d544456b7d 100644
--- a/calendar/externallib.php
+++ b/calendar/externallib.php
@@ -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),
]
);
}
diff --git a/calendar/templates/month_mini.mustache b/calendar/templates/month_mini.mustache
index cb3e22974c0..d5cef7239f7 100644
--- a/calendar/templates/month_mini.mustache
+++ b/calendar/templates/month_mini.mustache
@@ -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}}
diff --git a/calendar/tests/externallib_test.php b/calendar/tests/externallib_test.php
index 810c25fdd20..acf2294b794 100644
--- a/calendar/tests/externallib_test.php
+++ b/calendar/tests/externallib_test.php
@@ -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.
*/
diff --git a/version.php b/version.php
index 8af8c55e805..cd8b7bdfe31 100644
--- a/version.php
+++ b/version.php
@@ -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