From 8a2c797cc05b3ddf75a4ccecca1dc04ad33506df Mon Sep 17 00:00:00 2001 From: Jun Pataleta Date: Wed, 21 Jul 2021 23:49:23 +0800 Subject: [PATCH] MDL-71817 calendar: Set the calendar view mode properly for month view * Store the view mode of the calendar in the calendar_information object. * Let the month exporter handle the production of context data by moving 'viewingmonth', 'showviewselector', and 'viewinginblock' inside it. * Set the proper calendar view mode in the core_calendar/month_detailed template. * Pass the calendar view mode to the core_calendar_get_calendar_monthly_view WS function. --- calendar/amd/build/repository.min.js | 2 +- calendar/amd/build/repository.min.js.map | 2 +- calendar/amd/build/view_manager.min.js | 2 +- calendar/amd/build/view_manager.min.js.map | 2 +- calendar/amd/src/repository.js | 4 +++- calendar/amd/src/view_manager.js | 7 +++--- calendar/classes/external/month_exporter.php | 18 +++++++++++++- calendar/externallib.php | 22 ++++++++++------- calendar/lib.php | 25 +++++++++++++++++--- calendar/templates/month_detailed.mustache | 2 +- 10 files changed, 63 insertions(+), 23 deletions(-) diff --git a/calendar/amd/build/repository.min.js b/calendar/amd/build/repository.min.js index e04ceb50e4d..c75808e638d 100644 --- a/calendar/amd/build/repository.min.js +++ b/calendar/amd/build/repository.min.js @@ -1,2 +1,2 @@ -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 * @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 +{"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","view","courseid","categoryid","includenavigation","getCalendarDayData","updateEventStartDay","dayTimestamp","daytimestamp","getCalendarUpcomingData","getCourseGroupsData"],"mappings":"sTAsBA,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,2BAyBA,GAAME,CAAAA,CAAoB,CAAG,SAACC,CAAD,CAAOC,CAAP,CAAcC,CAAd,CAAwBC,CAAxB,CAAoCC,CAApC,CAAuDC,CAAvD,CAAyF,IAA5BC,CAAAA,CAA4B,wDAAtB,CAAsB,CAAnBC,CAAmB,wDAAZ,OAAY,CAezH,MAAOnB,WAAKC,IAAL,CAAU,CAdD,CACZC,UAAU,CAAE,yCADA,CAEZC,IAAI,CAAE,CACFS,IAAI,CAAJA,CADE,CAEFC,KAAK,CAALA,CAFE,CAGFO,QAAQ,CAAEN,CAHR,CAIFO,UAAU,CAAEN,CAJV,CAKFO,iBAAiB,CAAEN,CALjB,CAMFC,IAAI,CAAJA,CANE,CAOFC,GAAG,CAAHA,CAPE,CAQFC,IAAI,CAAJA,CARE,CAFM,CAcC,CAAV,EAAqB,CAArB,CACV,CAhBM,C,yBA6BA,GAAMI,CAAAA,CAAkB,CAAG,SAACX,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,CAIFE,QAAQ,CAAEN,CAJR,CAKFO,UAAU,CAAEN,CALV,CAFM,CAWC,CAAV,EAAqB,CAArB,CACV,CAbM,C,uBAwBA,GAAMS,CAAAA,CAAmB,CAAG,SAAC1B,CAAD,CAAU2B,CAAV,CAA2B,CAS1D,MAAOzB,WAAKC,IAAL,CAAU,CARD,CACZC,UAAU,CAAE,sCADA,CAEZC,IAAI,CAAE,CACFE,OAAO,CAAEP,CADP,CAEF4B,YAAY,CAAED,CAFZ,CAFM,CAQC,CAAV,EAAqB,CAArB,CACV,CAVM,C,wBAoBA,GAAME,CAAAA,CAAuB,CAAG,SAACb,CAAD,CAAWC,CAAX,CAA0B,CAS7D,MAAOf,WAAKC,IAAL,CAAU,CARD,CACZC,UAAU,CAAE,0CADA,CAEZC,IAAI,CAAE,CACFiB,QAAQ,CAAEN,CADR,CAEFO,UAAU,CAAEN,CAFV,CAFM,CAQC,CAAV,EAAqB,CAArB,CACV,CAVM,C,4BAkBA,GAAMa,CAAAA,CAAmB,CAAG,SAACd,CAAD,CAAc,CAQ7C,MAAOd,WAAKC,IAAL,CAAU,CAPD,CACZC,UAAU,CAAE,8BADA,CAEZC,IAAI,CAAE,CACFiB,QAAQ,CAAEN,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 * @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 * @param {string} view The calendar view mode.\n * @return {promise} Resolved with the month view data.\n */\nexport const getCalendarMonthData = (year, month, courseId, categoryId, includeNavigation, mini, day = 1, view = 'month') => {\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 view,\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 a6b0df8d024..a3eb6a00186 100644 --- a/calendar/amd/build/view_manager.min.js +++ b/calendar/amd/build/view_manager.min.js @@ -1,2 +1,2 @@ -function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}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","core/pending"],function(a,b,c,d,e,f,g,h,i,j,k,l){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=a.reloadCurrentUpcoming=a.updateUrl=a.changeDay=a.reloadCurrentDay=a.refreshDayContent=a.reloadCurrentMonth=a.changeMonth=a.refreshMonthContent=void 0;b=o(b);c=o(c);d=o(d);e=n(e);f=o(f);g=n(g);h=o(h);i=o(i);j=o(j);k=o(k);l=o(l);function m(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;m=function(){return a};return a}function n(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=m();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function o(a){return a&&a.__esModule?a:{default:a}}var p=function(a){a=(0,b.default)(a);a.on("click",g.links.eventLink,function(a){var b=a.target,c=null,d=null,e=new l.default("core_calendar/view_manager:eventLink:click");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();B(d).then(e.resolve).catch()}else{e.resolve()}});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){r(a,h.href,h.dataset.year,h.dataset.month,e,f,h.dataset.day);b.preventDefault()}else if("day"===d){v(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){q(a,f,g,i,j,a,"core_calendar/calendar_month",h).then(function(){w("?view=month")}).fail(d.default.exception)}else if("day"==e){t(a,f,g,h,i,j,a,"core_calendar/calendar_day").then(function(){w("?view=day")}).fail(d.default.exception)}else if("upcoming"==e){z(a,i,j,a,"core_calendar/calendar_upcoming").then(function(){w("?view=upcoming")}).fail(d.default.exception)}})},q=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 * @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';\nimport Pending from 'core/pending';\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 const pendingPromise = new Pending('core_calendar/view_manager:eventLink:click');\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 .then(pendingPromise.resolve)\n .catch();\n } else {\n pendingPromise.resolve();\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 updateUrl('?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 updateUrl('?view=day');\n }).fail(Notification.exception);\n } else if (view == 'upcoming') {\n reloadCurrentUpcoming(root, courseId, categoryId, root, 'core_calendar/calendar_upcoming')\n .then(() => {\n updateUrl('?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 context.showviewselector = !mini;\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 CustomEvent(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 updateUrl(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 context.showviewselector = 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 CustomEvent(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 updateUrl(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 * Update calendar URL.\n *\n * @param {String} url The calendar url to be updated.\n */\nexport const updateUrl = (url) => {\n const viewingFullCalendar = document.getElementById(CalendarSelectors.fullCalendarView);\n\n // We want to update the url only if the user is viewing the full calendar.\n if (viewingFullCalendar) {\n window.history.pushState({}, '', url);\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 {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 */\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 context.showviewselector = 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 CustomEvent(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 * @returns {Promise}\n */\nconst renderEventSummaryModal = (eventId) => {\n const pendingPromise = new Pending('core_calendar/view_manager:renderEventSummaryModal');\n\n // Calendar repository promise.\n return CalendarRepository.getEventById(eventId)\n .then((getEventResponse) => {\n if (!getEventResponse.event) {\n throw new Error('Error encountered while trying to fetch calendar event with ID: ' + eventId);\n }\n\n return getEventResponse.event;\n })\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: getEventTypeClassFromType(eventData.normalisedeventtype),\n isactionevent: eventData.isactionevent,\n url: eventData.url,\n action: eventData.action\n }\n };\n\n // Create the modal.\n return ModalFactory.create(modalParams);\n })\n .then(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 return modal;\n })\n .then(modal => {\n pendingPromise.resolve();\n\n return modal;\n })\n .catch(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 +{"version":3,"sources":["../src/view_manager.js"],"names":["registerEventListeners","root","on","CalendarSelectors","links","eventLink","e","target","eventId","pendingPromise","Pending","matches","actions","viewEvent","closest","dataset","querySelector","preventDefault","stopPropagation","renderEventSummaryModal","then","resolve","catch","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","updateUrl","fail","Notification","exception","refreshDayContent","reloadCurrentUpcoming","template","startLoading","attr","M","util","js_pending","get","join","includenavigation","mini","viewMode","CalendarRepository","getCalendarMonthData","context","Templates","render","html","js","replaceNode","document","dispatchEvent","CustomEvent","CalendarEvents","viewUpdated","always","js_complete","stopLoading","url","length","args","trigger","monthChanged","reloadCurrentMonth","getCalendarDayData","viewingday","showviewselector","reloadCurrentDay","dayChanged","viewingFullCalendar","getElementById","fullCalendarView","window","history","pushState","loadingIconContainer","containers","loadingIcon","removeClass","addClass","getCalendarUpcomingData","viewingupcoming","getEventTypeClassFromType","eventType","getEventById","getEventResponse","event","Error","eventData","modalParams","title","name","type","SummaryModal","TYPE","body","templateContext","canedit","candelete","headerclasses","normalisedeventtype","isactionevent","action","ModalFactory","create","modal","getRoot","ModalEvents","hidden","destroy","show","init"],"mappings":"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","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 * @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';\nimport Pending from 'core/pending';\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 const pendingPromise = new Pending('core_calendar/view_manager:eventLink:click');\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 .then(pendingPromise.resolve)\n .catch();\n } else {\n pendingPromise.resolve();\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' || view === 'monthblock') {\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 updateUrl('?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 updateUrl('?view=day');\n }).fail(Notification.exception);\n } else if (view == 'upcoming') {\n reloadCurrentUpcoming(root, courseId, categoryId, root, 'core_calendar/calendar_upcoming')\n .then(() => {\n updateUrl('?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 const viewMode = target.data('view');\n return CalendarRepository.getCalendarMonthData(year, month, courseId, categoryId, includenavigation, mini, day, viewMode)\n .then(context => {\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 CustomEvent(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 updateUrl(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 context.showviewselector = 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 CustomEvent(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 updateUrl(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 * Update calendar URL.\n *\n * @param {String} url The calendar url to be updated.\n */\nexport const updateUrl = (url) => {\n const viewingFullCalendar = document.getElementById(CalendarSelectors.fullCalendarView);\n\n // We want to update the url only if the user is viewing the full calendar.\n if (viewingFullCalendar) {\n window.history.pushState({}, '', url);\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 {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 */\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 context.showviewselector = 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 CustomEvent(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 * @returns {Promise}\n */\nconst renderEventSummaryModal = (eventId) => {\n const pendingPromise = new Pending('core_calendar/view_manager:renderEventSummaryModal');\n\n // Calendar repository promise.\n return CalendarRepository.getEventById(eventId)\n .then((getEventResponse) => {\n if (!getEventResponse.event) {\n throw new Error('Error encountered while trying to fetch calendar event with ID: ' + eventId);\n }\n\n return getEventResponse.event;\n })\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: getEventTypeClassFromType(eventData.normalisedeventtype),\n isactionevent: eventData.isactionevent,\n url: eventData.url,\n action: eventData.action\n }\n };\n\n // Create the modal.\n return ModalFactory.create(modalParams);\n })\n .then(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 return modal;\n })\n .then(modal => {\n pendingPromise.resolve();\n\n return modal;\n })\n .catch(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 1f2ff8ab9f3..030f76ac90a 100644 --- a/calendar/amd/src/repository.js +++ b/calendar/amd/src/repository.js @@ -92,9 +92,10 @@ export const submitCreateUpdateForm = (formData) => { * @param {boolean} includeNavigation Whether to include navigation. * @param {boolean} mini Whether the month is in mini view. * @param {number} day Day (optional) + * @param {string} view The calendar view mode. * @return {promise} Resolved with the month view data. */ -export const getCalendarMonthData = (year, month, courseId, categoryId, includeNavigation, mini, day = 1) => { +export const getCalendarMonthData = (year, month, courseId, categoryId, includeNavigation, mini, day = 1, view = 'month') => { const request = { methodname: 'core_calendar_get_calendar_monthly_view', args: { @@ -105,6 +106,7 @@ export const getCalendarMonthData = (year, month, courseId, categoryId, includeN includenavigation: includeNavigation, mini, day, + view, } }; diff --git a/calendar/amd/src/view_manager.js b/calendar/amd/src/view_manager.js index a0494b01628..892e3bb7019 100644 --- a/calendar/amd/src/view_manager.js +++ b/calendar/amd/src/view_manager.js @@ -83,7 +83,7 @@ const registerEventListeners = (root) => { const categoryId = wrapper.data('categoryid'); const link = e.currentTarget; - if (view === 'month') { + if (view === 'month' || view === 'monthblock') { changeMonth(root, link.href, link.dataset.year, link.dataset.month, courseId, categoryId, link.dataset.day); e.preventDefault(); } else if (view === 'day') { @@ -152,10 +152,9 @@ export const refreshMonthContent = (root, year, month, courseId, categoryId, tar 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) + const viewMode = target.data('view'); + return CalendarRepository.getCalendarMonthData(year, month, courseId, categoryId, includenavigation, mini, day, viewMode) .then(context => { - context.viewingmonth = true; - context.showviewselector = !mini; return Templates.render(template, context); }) .then((html, js) => { diff --git a/calendar/classes/external/month_exporter.php b/calendar/classes/external/month_exporter.php index 9f441f3320d..2d9e7963f40 100644 --- a/calendar/classes/external/month_exporter.php +++ b/calendar/classes/external/month_exporter.php @@ -204,6 +204,18 @@ class month_exporter extends exporter { 'type' => PARAM_INT, 'default' => 0, ], + 'viewingmonth' => [ + 'type' => PARAM_BOOL, + 'default' => true, + ], + 'showviewselector' => [ + 'type' => PARAM_BOOL, + 'default' => true, + ], + 'viewinginblock' => [ + 'type' => PARAM_BOOL, + 'default' => false, + ], ]; } @@ -224,11 +236,13 @@ class month_exporter extends exporter { $previousperiodlink = new moodle_url($this->url); $previousperiodlink->param('time', $previousperiod[0]); + $viewmode = $this->calendar->get_viewmode() ?? 'month'; + $return = [ 'courseid' => $this->calendar->courseid, 'weeks' => $this->get_weeks($output), 'daynames' => $this->get_day_names($output), - 'view' => 'month', + 'view' => $viewmode, 'date' => (new date_exporter($date))->export($output), 'periodname' => userdate($this->calendar->time, get_string('strftimemonthyear')), 'previousperiod' => (new date_exporter($previousperiod))->export($output), @@ -242,6 +256,8 @@ class month_exporter extends exporter { 'includenavigation' => $this->includenavigation, 'initialeventsloaded' => $this->initialeventsloaded, 'calendarinstanceid' => $this->calendarinstanceid, + 'showviewselector' => $viewmode === 'month', + 'viewinginblock' => $viewmode === 'monthblock', ]; if ($this->showcoursefilter) { diff --git a/calendar/externallib.php b/calendar/externallib.php index b2c94b546b0..8c52e713556 100644 --- a/calendar/externallib.php +++ b/calendar/externallib.php @@ -984,16 +984,18 @@ class core_calendar_external extends external_api { /** * Get data for the monthly calendar view. * - * @param int $year The year to be shown - * @param int $month The month to be shown - * @param int $courseid The course to be included - * @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 + * @param int $year The year to be shown + * @param int $month The month to be shown + * @param int $courseid The course to be included + * @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 + * @param string|null $view The view mode for the calendar. * @return array */ - public static function get_calendar_monthly_view($year, $month, $courseid, $categoryid, $includenavigation, $mini, $day) { + public static function get_calendar_monthly_view($year, $month, $courseid, $categoryid, $includenavigation, $mini, $day, + ?string $view = null) { global $USER, $PAGE; // Parameter validation. @@ -1005,6 +1007,7 @@ class core_calendar_external extends external_api { 'includenavigation' => $includenavigation, 'mini' => $mini, 'day' => $day, + 'view' => $view, ]); $context = \context_user::instance($USER->id); @@ -1017,7 +1020,7 @@ class core_calendar_external extends external_api { $calendar = \calendar_information::create($time, $params['courseid'], $params['categoryid']); self::validate_context($calendar->context); - $view = $params['mini'] ? 'mini' : 'month'; + $view = $params['view'] ?? ($params['mini'] ? 'mini' : 'month'); list($data, $template) = calendar_get_view($calendar, $view, $params['includenavigation']); return $data; @@ -1050,6 +1053,7 @@ class core_calendar_external extends external_api { NULL_ALLOWED ), 'day' => new external_value(PARAM_INT, 'Day to be viewed', VALUE_DEFAULT, 1), + 'view' => new external_value(PARAM_ALPHA, 'The view mode of the calendar', VALUE_DEFAULT, 'month', NULL_ALLOWED), ] ); } diff --git a/calendar/lib.php b/calendar/lib.php index ee86d968e63..4d19e836d50 100644 --- a/calendar/lib.php +++ b/calendar/lib.php @@ -1057,6 +1057,9 @@ class calendar_information { /** @var context The anticipated context that the calendar is viewed in */ public $context = null; + /** @var string The calendar's view mode. */ + protected $viewmode; + /** * Creates a new instance * @@ -1316,6 +1319,24 @@ class calendar_information { $block->title = get_string('monthlyview', 'calendar'); $renderer->add_pretend_calendar_block($block, BLOCK_POS_RIGHT); } + + /** + * Getter method for the calendar's view mode. + * + * @return string + */ + public function get_viewmode(): string { + return $this->viewmode; + } + + /** + * Setter method for the calendar's view mode. + * + * @param string $viewmode + */ + public function set_viewmode(string $viewmode): void { + $this->viewmode = $viewmode; + } } /** @@ -3493,15 +3514,13 @@ function calendar_get_view(\calendar_information $calendar, $view, $includenavig ]; $data = []; + $calendar->set_viewmode($view); if ($view == "month" || $view == "monthblock" || $view == "mini" || $view == "minithree" ) { $month = new \core_calendar\external\month_exporter($calendar, $type, $related); $month->set_includenavigation($includenavigation); $month->set_initialeventsloaded(!$skipevents); $month->set_showcoursefilter(($view == "month" || $view == "monthblock")); $data = $month->export($renderer); - $data->viewingmonth = true; - $data->showviewselector = ($view == "month"); - $data->viewinginblock = ($view == "monthblock"); } else if ($view == "day") { $day = new \core_calendar\external\calendar_day_exporter($calendar, $related); $data = $day->export($renderer); diff --git a/calendar/templates/month_detailed.mustache b/calendar/templates/month_detailed.mustache index 306dd47001d..59a530011b6 100644 --- a/calendar/templates/month_detailed.mustache +++ b/calendar/templates/month_detailed.mustache @@ -38,7 +38,7 @@ }} data-context-id="{{defaulteventcontext}}"{{! }} data-month="{{date.mon}}"{{! }} data-year="{{date.year}}"{{! - }} data-view="month"{{! + }} data-view="{{view}}"{{! }}> {{> core_calendar/month_navigation }} {{> core/overlay_loading}}