From b19b9cb8bf2a248992126f054fa8a46e9b247ccc Mon Sep 17 00:00:00 2001 From: Meirza Date: Fri, 7 Jun 2024 13:44:03 +0700 Subject: [PATCH] MDL-81644 calendar: The behaviour of event dates in the block calendar There is a difference in the behaviour of the calendar block when it is on the calendar page and when it is not. On the calendar page, when the user clicks on the date or link next/previous month or day name in the calendar block, it will have the effect of changing the URL, which should not happen. The patch also includes hiding popover after the user clicks the day number. When the user clicks on the date or is focused on the date and then presses enter on the keyboard, the popover does not automatically close. To fix this, I added an event type, "click", to be attached to the hidePopover function and added conditioning to the target element when there was a "click" event. An additional step was added to the Behat calendar for the click event to ease the testing process. For the popover, I set the "animation" to false to avoid the random Behat failure caused by the slow animation. --- .../calendar_month/block_calendar_month.php | 3 ++ .../tests/behat/block_calendar_month.feature | 19 +++++++++ calendar/amd/build/calendar.min.js | 2 +- calendar/amd/build/calendar.min.js.map | 2 +- calendar/amd/build/calendar_view.min.js | 2 +- calendar/amd/build/calendar_view.min.js.map | 2 +- calendar/amd/build/popover.min.js | 2 +- calendar/amd/build/popover.min.js.map | 2 +- calendar/amd/build/view_manager.min.js | 2 +- calendar/amd/build/view_manager.min.js.map | 2 +- calendar/amd/src/calendar.js | 25 +++++++---- calendar/amd/src/calendar_view.js | 6 +-- calendar/amd/src/popover.js | 18 +++++++- calendar/amd/src/view_manager.js | 42 +++++++++++++------ calendar/templates/calendar_day.mustache | 4 +- calendar/templates/calendar_month.mustache | 4 +- calendar/tests/behat/behat_calendar.php | 34 +++++++++++++++ 17 files changed, 136 insertions(+), 35 deletions(-) diff --git a/blocks/calendar_month/block_calendar_month.php b/blocks/calendar_month/block_calendar_month.php index fe3b998a6c8..96350fd5119 100644 --- a/blocks/calendar_month/block_calendar_month.php +++ b/blocks/calendar_month/block_calendar_month.php @@ -56,6 +56,9 @@ class block_calendar_month extends block_base { $calendar = \calendar_information::create(time(), $courseid, $categoryid); list($data, $template) = calendar_get_view($calendar, 'monthblock', isloggedin()); + // Add a flag that this is coming from calendar block. + $data->iscalendarblock = true; + $renderer = $this->page->get_renderer('core_calendar'); $this->content->text .= $renderer->render_from_template($template, $data); diff --git a/blocks/calendar_month/tests/behat/block_calendar_month.feature b/blocks/calendar_month/tests/behat/block_calendar_month.feature index 08481025931..691f5b95afd 100644 --- a/blocks/calendar_month/tests/behat/block_calendar_month.feature +++ b/blocks/calendar_month/tests/behat/block_calendar_month.feature @@ -90,3 +90,22 @@ Feature: Enable the calendar block in a course and test it's functionality Then I should see "Group Event" And I am on the "Course 1" course page logged in as student2 And I should not see "Group Event" + + @javascript + Scenario: Click on today's course event on the calendar view page's calendar block + Given I log in as "admin" + And I create a calendar event with form data: + | id_eventtype | Site | + | id_name | Site Event | + And I am on site homepage + And I turn editing mode on + And I add the "Calendar" block + And I configure the "Calendar" block + And I set the following fields to these values: + | Page contexts | Display throughout the entire site | + And I press "Save changes" + When I am on "Course 1" course homepage + And I follow "Course calendar" + And I click on today in the mini-calendar block + Then I should see "Site Event" in the "Calendar" "block" + And ".popover" "css_element" should not exist diff --git a/calendar/amd/build/calendar.min.js b/calendar/amd/build/calendar.min.js index 117ff46a1e4..75b98b5e5ce 100644 --- a/calendar/amd/build/calendar.min.js +++ b/calendar/amd/build/calendar.min.js @@ -9,6 +9,6 @@ * @copyright 2017 Simey Lameze * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("core_calendar/calendar",["jquery","core/templates","core/notification","core_calendar/repository","core_calendar/events","core_calendar/view_manager","core_calendar/crud","core_calendar/selectors","core/config","core/url","core/str"],(function($,Templates,Notification,CalendarRepository,CalendarEvents,CalendarViewManager,CalendarCrud,CalendarSelectors,Config,Url,Str){var SELECTORS_DAY="[data-region='day']",SELECTORS_DAY_CONTENT="[data-region='day-content']",SELECTORS_LOADING_ICON=".loading-icon",SELECTORS_VIEW_DAY_LINK="[data-action='view-day-link']",SELECTORS_CALENDAR_MONTH_WRAPPER=".calendarwrapper",SELECTORS_SCREEN_READER_ANNOUNCEMENTS=".calendar-announcements",SELECTORS_CURRENT_MONTH=".calendar-controls .current",handleMoveEvent=function(e,eventId,originElement,destinationElement){var originTimestamp=null,destinationTimestamp=destinationElement.attr("data-day-timestamp");originElement&&(originTimestamp=originElement.attr("data-day-timestamp")),originElement&&originTimestamp==destinationTimestamp||Templates.render("core/loading",{}).then((function(html,js){destinationElement.find(SELECTORS_DAY_CONTENT).addClass("hidden"),Templates.appendNodeContents(destinationElement,html,js),originElement&&(originElement.find(SELECTORS_DAY_CONTENT).addClass("hidden"),Templates.appendNodeContents(originElement,html,js))})).then((function(){return CalendarRepository.updateEventStartDay(eventId,destinationTimestamp)})).then((function(){$("body").trigger(CalendarEvents.eventMoved,[eventId,originElement,destinationElement])})).always((function(){var destinationLoadingElement=destinationElement.find(SELECTORS_LOADING_ICON);if(destinationElement.find(SELECTORS_DAY_CONTENT).removeClass("hidden"),Templates.replaceNode(destinationLoadingElement,"",""),originElement){var originLoadingElement=originElement.find(SELECTORS_LOADING_ICON);originElement.find(SELECTORS_DAY_CONTENT).removeClass("hidden"),Templates.replaceNode(originLoadingElement,"","")}})).catch(Notification.exception)},registerEventListeners=function(root){const viewingFullCalendar=document.getElementById(CalendarSelectors.fullCalendarView);root.on("click",SELECTORS_VIEW_DAY_LINK,(function(e){var dayLink=$(e.target).closest(SELECTORS_VIEW_DAY_LINK),year=dayLink.data("year"),month=dayLink.data("month"),day=dayLink.data("day"),courseId=dayLink.data("courseid"),categoryId=dayLink.data("categoryid");const urlParams={view:"day",time:dayLink.data("timestamp"),course:courseId};if(viewingFullCalendar){const urlParamString=Object.entries(urlParams).map((_ref=>{let[key,value]=_ref;return"".concat(encodeURIComponent(key),"=").concat(encodeURIComponent(value))})).join("&");CalendarViewManager.refreshDayContent(root,year,month,day,courseId,categoryId,root,"core_calendar/calendar_day").then((function(){return e.preventDefault(),CalendarViewManager.updateUrl(urlParamString)})).catch(Notification.exception)}else window.location.assign(Url.relativeUrl("calendar/view.php",urlParams))})),root.on("change",CalendarSelectors.elements.courseSelector,(function(){var selectElement=$(this),courseId=selectElement.val();const courseName=$("option:selected",selectElement).text();CalendarViewManager.reloadCurrentMonth(root,courseId,null).then((function(){return root.find(CalendarSelectors.elements.courseSelector).val(courseId)})).then((function(){CalendarViewManager.updateUrl("?view=month&course="+courseId),CalendarViewManager.handleCourseChange(Number(courseId),courseName)})).catch(Notification.exception)}));var eventFormPromise=CalendarCrud.registerEventFormModal(root),contextId=$(SELECTORS_CALENDAR_MONTH_WRAPPER).data("context-id");!function(root,eventFormModalPromise){var body=$("body");body.on(CalendarEvents.created,(function(){CalendarViewManager.reloadCurrentMonth(root)})),body.on(CalendarEvents.deleted,(function(){CalendarViewManager.reloadCurrentMonth(root)})),body.on(CalendarEvents.updated,(function(){CalendarViewManager.reloadCurrentMonth(root)})),body.on(CalendarEvents.editActionEvent,(function(e,url){window.location.assign(url)})),body.on(CalendarEvents.moveEvent,handleMoveEvent),body.on(CalendarEvents.eventMoved,(function(){CalendarViewManager.reloadCurrentMonth(root)})),body.on(CalendarEvents.monthChanged,root,(async function(){const monthName=body.find(SELECTORS_CURRENT_MONTH).text(),monthAnnoucement=await Str.get_string("newmonthannouncement","calendar",monthName);body.find(SELECTORS_SCREEN_READER_ANNOUNCEMENTS).html(monthAnnoucement)})),CalendarCrud.registerEditListeners(root,eventFormModalPromise)}(root,eventFormPromise),contextId&&root.on("click",SELECTORS_DAY,(function(e){var target=$(e.target);const displayingSmallBlockCalendar="side-pre"===root.parents("aside").data("blockregion");if(!viewingFullCalendar&&displayingSmallBlockCalendar){const dateContainer=target.closest(SELECTORS_DAY),courseId=target.closest(CalendarSelectors.wrapper).data("courseid"),params={view:"day",time:dateContainer.data("day-timestamp"),course:courseId};window.location.assign(Url.relativeUrl("calendar/view.php",params))}else{if(!target.closest(SELECTORS_VIEW_DAY_LINK).length){var startTime=$(this).attr("data-new-event-timestamp");eventFormPromise.then((function(modal){var wrapper=target.closest(CalendarSelectors.wrapper);modal.setCourseId(wrapper.data("courseid"));var categoryId=wrapper.data("categoryid");void 0!==categoryId&&modal.setCategoryId(categoryId),modal.setContextId(wrapper.data("contextId")),modal.setStartTime(startTime),modal.show()})).catch(Notification.exception)}}e.preventDefault()}))};return{init:function(root){root=$(root),CalendarViewManager.init(root),registerEventListeners(root)}}})); +define("core_calendar/calendar",["jquery","core/templates","core/notification","core_calendar/repository","core_calendar/events","core_calendar/view_manager","core_calendar/crud","core_calendar/selectors","core/url","core/str"],(function($,Templates,Notification,CalendarRepository,CalendarEvents,CalendarViewManager,CalendarCrud,CalendarSelectors,Url,Str){var SELECTORS_DAY="[data-region='day']",SELECTORS_DAY_CONTENT="[data-region='day-content']",SELECTORS_LOADING_ICON=".loading-icon",SELECTORS_VIEW_DAY_LINK="[data-action='view-day-link']",SELECTORS_CALENDAR_MONTH_WRAPPER=".calendarwrapper",SELECTORS_SCREEN_READER_ANNOUNCEMENTS=".calendar-announcements",SELECTORS_CURRENT_MONTH=".calendar-controls .current",handleMoveEvent=function(e,eventId,originElement,destinationElement){var originTimestamp=null,destinationTimestamp=destinationElement.attr("data-day-timestamp");originElement&&(originTimestamp=originElement.attr("data-day-timestamp")),originElement&&originTimestamp==destinationTimestamp||Templates.render("core/loading",{}).then((function(html,js){destinationElement.find(SELECTORS_DAY_CONTENT).addClass("hidden"),Templates.appendNodeContents(destinationElement,html,js),originElement&&(originElement.find(SELECTORS_DAY_CONTENT).addClass("hidden"),Templates.appendNodeContents(originElement,html,js))})).then((function(){return CalendarRepository.updateEventStartDay(eventId,destinationTimestamp)})).then((function(){$("body").trigger(CalendarEvents.eventMoved,[eventId,originElement,destinationElement])})).always((function(){var destinationLoadingElement=destinationElement.find(SELECTORS_LOADING_ICON);if(destinationElement.find(SELECTORS_DAY_CONTENT).removeClass("hidden"),Templates.replaceNode(destinationLoadingElement,"",""),originElement){var originLoadingElement=originElement.find(SELECTORS_LOADING_ICON);originElement.find(SELECTORS_DAY_CONTENT).removeClass("hidden"),Templates.replaceNode(originLoadingElement,"","")}})).catch(Notification.exception)},registerEventListeners=function(root,isCalendarBlock){const viewingFullCalendar=document.getElementById(CalendarSelectors.fullCalendarView);root.on("click",SELECTORS_VIEW_DAY_LINK,(function(e){var dayLink=$(e.target).closest(SELECTORS_VIEW_DAY_LINK),year=dayLink.data("year"),month=dayLink.data("month"),day=dayLink.data("day"),courseId=dayLink.data("courseid"),categoryId=dayLink.data("categoryid");const urlParams={view:"day",time:dayLink.data("timestamp"),course:courseId};if(viewingFullCalendar){const urlParamString=Object.entries(urlParams).map((_ref=>{let[key,value]=_ref;return"".concat(encodeURIComponent(key),"=").concat(encodeURIComponent(value))})).join("&");CalendarViewManager.refreshDayContent(root,year,month,day,courseId,categoryId,root,"core_calendar/calendar_day",isCalendarBlock).then((function(){e.preventDefault(),isCalendarBlock||CalendarViewManager.updateUrl("?"+urlParamString)})).catch(Notification.exception)}else window.location.assign(Url.relativeUrl("calendar/view.php",urlParams))})),root.on("change",CalendarSelectors.elements.courseSelector,(function(){var selectElement=$(this),courseId=selectElement.val();const courseName=$("option:selected",selectElement).text();CalendarViewManager.reloadCurrentMonth(root,courseId,null).then((function(){return root.find(CalendarSelectors.elements.courseSelector).val(courseId)})).then((function(){CalendarViewManager.updateUrl("?view=month&course="+courseId),CalendarViewManager.handleCourseChange(Number(courseId),courseName)})).catch(Notification.exception)}));var eventFormPromise=CalendarCrud.registerEventFormModal(root),contextId=$(SELECTORS_CALENDAR_MONTH_WRAPPER).data("context-id");!function(root,eventFormModalPromise){var body=$("body");body.on(CalendarEvents.created,(function(){CalendarViewManager.reloadCurrentMonth(root)})),body.on(CalendarEvents.deleted,(function(){CalendarViewManager.reloadCurrentMonth(root)})),body.on(CalendarEvents.updated,(function(){CalendarViewManager.reloadCurrentMonth(root)})),body.on(CalendarEvents.editActionEvent,(function(e,url){window.location.assign(url)})),body.on(CalendarEvents.moveEvent,handleMoveEvent),body.on(CalendarEvents.eventMoved,(function(){CalendarViewManager.reloadCurrentMonth(root)})),body.on(CalendarEvents.monthChanged,root,(async function(){const monthName=body.find(SELECTORS_CURRENT_MONTH).text(),monthAnnoucement=await Str.get_string("newmonthannouncement","calendar",monthName);body.find(SELECTORS_SCREEN_READER_ANNOUNCEMENTS).html(monthAnnoucement)})),CalendarCrud.registerEditListeners(root,eventFormModalPromise)}(root,eventFormPromise),contextId&&root.on("click",SELECTORS_DAY,(function(e){var target=$(e.target);const displayingSmallBlockCalendar="side-pre"===root.parents("aside").data("blockregion");if(!viewingFullCalendar&&displayingSmallBlockCalendar){const dateContainer=target.closest(SELECTORS_DAY),courseId=target.closest(CalendarSelectors.wrapper).data("courseid"),params={view:"day",time:dateContainer.data("day-timestamp"),course:courseId};window.location.assign(Url.relativeUrl("calendar/view.php",params))}else{if(!target.closest(SELECTORS_VIEW_DAY_LINK).length){var startTime=$(this).attr("data-new-event-timestamp");eventFormPromise.then((function(modal){var wrapper=target.closest(CalendarSelectors.wrapper);modal.setCourseId(wrapper.data("courseid"));var categoryId=wrapper.data("categoryid");void 0!==categoryId&&modal.setCategoryId(categoryId),modal.setContextId(wrapper.data("contextId")),modal.setStartTime(startTime),modal.show()})).catch(Notification.exception)}}e.preventDefault()}))};return{init:function(root){let isCalendarBlock=arguments.length>1&&void 0!==arguments[1]&&arguments[1];root=$(root),CalendarViewManager.init(root,"month",isCalendarBlock),registerEventListeners(root,isCalendarBlock)}}})); //# sourceMappingURL=calendar.min.js.map \ No newline at end of file diff --git a/calendar/amd/build/calendar.min.js.map b/calendar/amd/build/calendar.min.js.map index ce0ac0f82e0..621e8998b97 100644 --- a/calendar/amd/build/calendar.min.js.map +++ b/calendar/amd/build/calendar.min.js.map @@ -1 +1 @@ -{"version":3,"file":"calendar.min.js","sources":["../src/calendar.js"],"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 * This module is the highest level module for the calendar. It is\n * responsible for initialising all of the components required for\n * the calendar to run. It also coordinates the interaction between\n * components by listening for and responding to different events\n * triggered within the calendar UI.\n *\n * @module core_calendar/calendar\n * @copyright 2017 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'core_calendar/repository',\n 'core_calendar/events',\n 'core_calendar/view_manager',\n 'core_calendar/crud',\n 'core_calendar/selectors',\n 'core/config',\n 'core/url',\n 'core/str',\n],\nfunction(\n $,\n Templates,\n Notification,\n CalendarRepository,\n CalendarEvents,\n CalendarViewManager,\n CalendarCrud,\n CalendarSelectors,\n Config,\n Url,\n Str,\n) {\n\n var SELECTORS = {\n ROOT: \"[data-region='calendar']\",\n DAY: \"[data-region='day']\",\n NEW_EVENT_BUTTON: \"[data-action='new-event-button']\",\n DAY_CONTENT: \"[data-region='day-content']\",\n LOADING_ICON: '.loading-icon',\n VIEW_DAY_LINK: \"[data-action='view-day-link']\",\n CALENDAR_MONTH_WRAPPER: \".calendarwrapper\",\n TODAY: '.today',\n DAY_NUMBER_CIRCLE: '.day-number-circle',\n DAY_NUMBER: '.day-number',\n SCREEN_READER_ANNOUNCEMENTS: '.calendar-announcements',\n CURRENT_MONTH: '.calendar-controls .current'\n };\n\n /**\n * Handler for the drag and drop move event. Provides a loading indicator\n * while the request is sent to the server to update the event start date.\n *\n * Triggers a eventMoved calendar javascript event if the event was successfully\n * updated.\n *\n * @param {event} e The calendar move event\n * @param {int} eventId The event id being moved\n * @param {object|null} originElement The jQuery element for where the event is moving from\n * @param {object} destinationElement The jQuery element for where the event is moving to\n */\n var handleMoveEvent = function(e, eventId, originElement, destinationElement) {\n var originTimestamp = null;\n var destinationTimestamp = destinationElement.attr('data-day-timestamp');\n\n if (originElement) {\n originTimestamp = originElement.attr('data-day-timestamp');\n }\n\n // If the event has actually changed day.\n if (!originElement || originTimestamp != destinationTimestamp) {\n Templates.render('core/loading', {})\n .then(function(html, js) {\n // First we show some loading icons in each of the days being affected.\n destinationElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');\n Templates.appendNodeContents(destinationElement, html, js);\n\n if (originElement) {\n originElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');\n Templates.appendNodeContents(originElement, html, js);\n }\n return;\n })\n .then(function() {\n // Send a request to the server to make the change.\n return CalendarRepository.updateEventStartDay(eventId, destinationTimestamp);\n })\n .then(function() {\n // If the update was successful then broadcast an event letting the calendar\n // know that an event has been moved.\n $('body').trigger(CalendarEvents.eventMoved, [eventId, originElement, destinationElement]);\n return;\n })\n .always(function() {\n // Always remove the loading icons regardless of whether the update\n // request was successful or not.\n var destinationLoadingElement = destinationElement.find(SELECTORS.LOADING_ICON);\n destinationElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');\n Templates.replaceNode(destinationLoadingElement, '', '');\n\n if (originElement) {\n var originLoadingElement = originElement.find(SELECTORS.LOADING_ICON);\n originElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');\n Templates.replaceNode(originLoadingElement, '', '');\n }\n return;\n })\n .catch(Notification.exception);\n }\n };\n\n /**\n * Listen to and handle any calendar events fired by the calendar UI.\n *\n * @method registerCalendarEventListeners\n * @param {object} root The calendar root element\n * @param {object} eventFormModalPromise A promise reolved with the event form modal\n */\n var registerCalendarEventListeners = function(root, eventFormModalPromise) {\n var body = $('body');\n\n body.on(CalendarEvents.created, function() {\n CalendarViewManager.reloadCurrentMonth(root);\n });\n body.on(CalendarEvents.deleted, function() {\n CalendarViewManager.reloadCurrentMonth(root);\n });\n body.on(CalendarEvents.updated, function() {\n CalendarViewManager.reloadCurrentMonth(root);\n });\n body.on(CalendarEvents.editActionEvent, function(e, url) {\n // Action events needs to be edit directly on the course module.\n window.location.assign(url);\n });\n // Handle the event fired by the drag and drop code.\n body.on(CalendarEvents.moveEvent, handleMoveEvent);\n // When an event is successfully moved we should updated the UI.\n body.on(CalendarEvents.eventMoved, function() {\n CalendarViewManager.reloadCurrentMonth(root);\n });\n // Announce the newly loaded month to screen readers.\n body.on(CalendarEvents.monthChanged, root, async function() {\n const monthName = body.find(SELECTORS.CURRENT_MONTH).text();\n const monthAnnoucement = await Str.get_string('newmonthannouncement', 'calendar', monthName);\n body.find(SELECTORS.SCREEN_READER_ANNOUNCEMENTS).html(monthAnnoucement);\n });\n\n CalendarCrud.registerEditListeners(root, eventFormModalPromise);\n };\n\n /**\n * Register event listeners for the module.\n *\n * @param {object} root The calendar root element\n */\n var registerEventListeners = function(root) {\n const viewingFullCalendar = document.getElementById(CalendarSelectors.fullCalendarView);\n // Listen the click on the day link to render the day view.\n root.on('click', SELECTORS.VIEW_DAY_LINK, function(e) {\n var dayLink = $(e.target).closest(SELECTORS.VIEW_DAY_LINK);\n var year = dayLink.data('year'),\n month = dayLink.data('month'),\n day = dayLink.data('day'),\n courseId = dayLink.data('courseid'),\n categoryId = dayLink.data('categoryid');\n const urlParams = {\n view: 'day',\n time: dayLink.data('timestamp'),\n course: courseId,\n };\n if (viewingFullCalendar) {\n // Construct the URL parameter string from the urlParams object.\n const urlParamString = Object.entries(urlParams)\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&');\n CalendarViewManager.refreshDayContent(root, year, month, day, courseId, categoryId, root,\n 'core_calendar/calendar_day').then(function() {\n e.preventDefault();\n return CalendarViewManager.updateUrl(urlParamString);\n }).catch(Notification.exception);\n } else {\n window.location.assign(Url.relativeUrl('calendar/view.php', urlParams));\n }\n });\n\n root.on('change', CalendarSelectors.elements.courseSelector, function() {\n var selectElement = $(this);\n var courseId = selectElement.val();\n const courseName = $(\"option:selected\", selectElement).text();\n CalendarViewManager.reloadCurrentMonth(root, courseId, null)\n .then(function() {\n // We need to get the selector again because the content has changed.\n return root.find(CalendarSelectors.elements.courseSelector).val(courseId);\n })\n .then(function() {\n CalendarViewManager.updateUrl('?view=month&course=' + courseId);\n CalendarViewManager.handleCourseChange(Number(courseId), courseName);\n return;\n })\n .catch(Notification.exception);\n });\n\n var eventFormPromise = CalendarCrud.registerEventFormModal(root),\n contextId = $(SELECTORS.CALENDAR_MONTH_WRAPPER).data('context-id');\n registerCalendarEventListeners(root, eventFormPromise);\n\n if (contextId) {\n // Bind click events to calendar days.\n root.on('click', SELECTORS.DAY, function(e) {\n var target = $(e.target);\n const displayingSmallBlockCalendar = root.parents('aside').data('blockregion') === 'side-pre';\n\n if (!viewingFullCalendar && displayingSmallBlockCalendar) {\n const dateContainer = target.closest(SELECTORS.DAY);\n const wrapper = target.closest(CalendarSelectors.wrapper);\n const courseId = wrapper.data('courseid');\n const params = {\n view: 'day',\n time: dateContainer.data('day-timestamp'),\n course: courseId,\n };\n window.location.assign(Url.relativeUrl('calendar/view.php', params));\n } else {\n const hasViewDayLink = target.closest(SELECTORS.VIEW_DAY_LINK).length;\n const shouldShowNewEventModal = !hasViewDayLink;\n if (shouldShowNewEventModal) {\n var startTime = $(this).attr('data-new-event-timestamp');\n eventFormPromise.then(function(modal) {\n var wrapper = target.closest(CalendarSelectors.wrapper);\n modal.setCourseId(wrapper.data('courseid'));\n\n var categoryId = wrapper.data('categoryid');\n if (typeof categoryId !== 'undefined') {\n modal.setCategoryId(categoryId);\n }\n\n modal.setContextId(wrapper.data('contextId'));\n modal.setStartTime(startTime);\n modal.show();\n return;\n }).catch(Notification.exception);\n }\n }\n e.preventDefault();\n });\n }\n };\n\n return {\n init: function(root) {\n root = $(root);\n CalendarViewManager.init(root);\n registerEventListeners(root);\n }\n };\n});\n"],"names":["define","$","Templates","Notification","CalendarRepository","CalendarEvents","CalendarViewManager","CalendarCrud","CalendarSelectors","Config","Url","Str","SELECTORS","handleMoveEvent","e","eventId","originElement","destinationElement","originTimestamp","destinationTimestamp","attr","render","then","html","js","find","addClass","appendNodeContents","updateEventStartDay","trigger","eventMoved","always","destinationLoadingElement","removeClass","replaceNode","originLoadingElement","catch","exception","registerEventListeners","root","viewingFullCalendar","document","getElementById","fullCalendarView","on","dayLink","target","closest","year","data","month","day","courseId","categoryId","urlParams","view","time","course","urlParamString","Object","entries","map","_ref","key","value","encodeURIComponent","join","refreshDayContent","preventDefault","updateUrl","window","location","assign","relativeUrl","elements","courseSelector","selectElement","this","val","courseName","text","reloadCurrentMonth","handleCourseChange","Number","eventFormPromise","registerEventFormModal","contextId","eventFormModalPromise","body","created","deleted","updated","editActionEvent","url","moveEvent","monthChanged","async","monthName","monthAnnoucement","get_string","registerEditListeners","registerCalendarEventListeners","displayingSmallBlockCalendar","parents","dateContainer","wrapper","params","length","startTime","modal","setCourseId","setCategoryId","setContextId","setStartTime","show","init"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"calendar.min.js","sources":["../src/calendar.js"],"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 * This module is the highest level module for the calendar. It is\n * responsible for initialising all of the components required for\n * the calendar to run. It also coordinates the interaction between\n * components by listening for and responding to different events\n * triggered within the calendar UI.\n *\n * @module core_calendar/calendar\n * @copyright 2017 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'core_calendar/repository',\n 'core_calendar/events',\n 'core_calendar/view_manager',\n 'core_calendar/crud',\n 'core_calendar/selectors',\n 'core/url',\n 'core/str',\n],\nfunction(\n $,\n Templates,\n Notification,\n CalendarRepository,\n CalendarEvents,\n CalendarViewManager,\n CalendarCrud,\n CalendarSelectors,\n Url,\n Str,\n) {\n\n var SELECTORS = {\n ROOT: \"[data-region='calendar']\",\n DAY: \"[data-region='day']\",\n NEW_EVENT_BUTTON: \"[data-action='new-event-button']\",\n DAY_CONTENT: \"[data-region='day-content']\",\n LOADING_ICON: '.loading-icon',\n VIEW_DAY_LINK: \"[data-action='view-day-link']\",\n CALENDAR_MONTH_WRAPPER: \".calendarwrapper\",\n TODAY: '.today',\n DAY_NUMBER_CIRCLE: '.day-number-circle',\n DAY_NUMBER: '.day-number',\n SCREEN_READER_ANNOUNCEMENTS: '.calendar-announcements',\n CURRENT_MONTH: '.calendar-controls .current'\n };\n\n /**\n * Handler for the drag and drop move event. Provides a loading indicator\n * while the request is sent to the server to update the event start date.\n *\n * Triggers a eventMoved calendar javascript event if the event was successfully\n * updated.\n *\n * @param {event} e The calendar move event\n * @param {int} eventId The event id being moved\n * @param {object|null} originElement The jQuery element for where the event is moving from\n * @param {object} destinationElement The jQuery element for where the event is moving to\n */\n var handleMoveEvent = function(e, eventId, originElement, destinationElement) {\n var originTimestamp = null;\n var destinationTimestamp = destinationElement.attr('data-day-timestamp');\n\n if (originElement) {\n originTimestamp = originElement.attr('data-day-timestamp');\n }\n\n // If the event has actually changed day.\n if (!originElement || originTimestamp != destinationTimestamp) {\n Templates.render('core/loading', {})\n .then(function(html, js) {\n // First we show some loading icons in each of the days being affected.\n destinationElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');\n Templates.appendNodeContents(destinationElement, html, js);\n\n if (originElement) {\n originElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');\n Templates.appendNodeContents(originElement, html, js);\n }\n return;\n })\n .then(function() {\n // Send a request to the server to make the change.\n return CalendarRepository.updateEventStartDay(eventId, destinationTimestamp);\n })\n .then(function() {\n // If the update was successful then broadcast an event letting the calendar\n // know that an event has been moved.\n $('body').trigger(CalendarEvents.eventMoved, [eventId, originElement, destinationElement]);\n return;\n })\n .always(function() {\n // Always remove the loading icons regardless of whether the update\n // request was successful or not.\n var destinationLoadingElement = destinationElement.find(SELECTORS.LOADING_ICON);\n destinationElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');\n Templates.replaceNode(destinationLoadingElement, '', '');\n\n if (originElement) {\n var originLoadingElement = originElement.find(SELECTORS.LOADING_ICON);\n originElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');\n Templates.replaceNode(originLoadingElement, '', '');\n }\n return;\n })\n .catch(Notification.exception);\n }\n };\n\n /**\n * Listen to and handle any calendar events fired by the calendar UI.\n *\n * @method registerCalendarEventListeners\n * @param {object} root The calendar root element\n * @param {object} eventFormModalPromise A promise reolved with the event form modal\n */\n var registerCalendarEventListeners = function(root, eventFormModalPromise) {\n var body = $('body');\n\n body.on(CalendarEvents.created, function() {\n CalendarViewManager.reloadCurrentMonth(root);\n });\n body.on(CalendarEvents.deleted, function() {\n CalendarViewManager.reloadCurrentMonth(root);\n });\n body.on(CalendarEvents.updated, function() {\n CalendarViewManager.reloadCurrentMonth(root);\n });\n body.on(CalendarEvents.editActionEvent, function(e, url) {\n // Action events needs to be edit directly on the course module.\n window.location.assign(url);\n });\n // Handle the event fired by the drag and drop code.\n body.on(CalendarEvents.moveEvent, handleMoveEvent);\n // When an event is successfully moved we should updated the UI.\n body.on(CalendarEvents.eventMoved, function() {\n CalendarViewManager.reloadCurrentMonth(root);\n });\n // Announce the newly loaded month to screen readers.\n body.on(CalendarEvents.monthChanged, root, async function() {\n const monthName = body.find(SELECTORS.CURRENT_MONTH).text();\n const monthAnnoucement = await Str.get_string('newmonthannouncement', 'calendar', monthName);\n body.find(SELECTORS.SCREEN_READER_ANNOUNCEMENTS).html(monthAnnoucement);\n });\n\n CalendarCrud.registerEditListeners(root, eventFormModalPromise);\n };\n\n /**\n * Register event listeners for the module.\n *\n * @param {object} root The calendar root element\n * @param {boolean} isCalendarBlock - A flag indicating whether this is a calendar block.\n */\n var registerEventListeners = function(root, isCalendarBlock) {\n const viewingFullCalendar = document.getElementById(CalendarSelectors.fullCalendarView);\n // Listen the click on the day link to render the day view.\n root.on('click', SELECTORS.VIEW_DAY_LINK, function(e) {\n var dayLink = $(e.target).closest(SELECTORS.VIEW_DAY_LINK);\n var year = dayLink.data('year'),\n month = dayLink.data('month'),\n day = dayLink.data('day'),\n courseId = dayLink.data('courseid'),\n categoryId = dayLink.data('categoryid');\n const urlParams = {\n view: 'day',\n time: dayLink.data('timestamp'),\n course: courseId,\n };\n if (viewingFullCalendar) {\n // Construct the URL parameter string from the urlParams object.\n const urlParamString = Object.entries(urlParams)\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&');\n CalendarViewManager.refreshDayContent(root, year, month, day, courseId, categoryId, root,\n 'core_calendar/calendar_day', isCalendarBlock).then(function() {\n e.preventDefault();\n // Update the URL if it's not calendar block.\n if (!isCalendarBlock) {\n CalendarViewManager.updateUrl('?' + urlParamString);\n }\n return;\n }).catch(Notification.exception);\n } else {\n window.location.assign(Url.relativeUrl('calendar/view.php', urlParams));\n }\n });\n\n root.on('change', CalendarSelectors.elements.courseSelector, function() {\n var selectElement = $(this);\n var courseId = selectElement.val();\n const courseName = $(\"option:selected\", selectElement).text();\n CalendarViewManager.reloadCurrentMonth(root, courseId, null)\n .then(function() {\n // We need to get the selector again because the content has changed.\n return root.find(CalendarSelectors.elements.courseSelector).val(courseId);\n })\n .then(function() {\n CalendarViewManager.updateUrl('?view=month&course=' + courseId);\n CalendarViewManager.handleCourseChange(Number(courseId), courseName);\n return;\n })\n .catch(Notification.exception);\n });\n\n var eventFormPromise = CalendarCrud.registerEventFormModal(root),\n contextId = $(SELECTORS.CALENDAR_MONTH_WRAPPER).data('context-id');\n registerCalendarEventListeners(root, eventFormPromise);\n\n if (contextId) {\n // Bind click events to calendar days.\n root.on('click', SELECTORS.DAY, function(e) {\n var target = $(e.target);\n const displayingSmallBlockCalendar = root.parents('aside').data('blockregion') === 'side-pre';\n\n if (!viewingFullCalendar && displayingSmallBlockCalendar) {\n const dateContainer = target.closest(SELECTORS.DAY);\n const wrapper = target.closest(CalendarSelectors.wrapper);\n const courseId = wrapper.data('courseid');\n const params = {\n view: 'day',\n time: dateContainer.data('day-timestamp'),\n course: courseId,\n };\n window.location.assign(Url.relativeUrl('calendar/view.php', params));\n } else {\n const hasViewDayLink = target.closest(SELECTORS.VIEW_DAY_LINK).length;\n const shouldShowNewEventModal = !hasViewDayLink;\n if (shouldShowNewEventModal) {\n var startTime = $(this).attr('data-new-event-timestamp');\n eventFormPromise.then(function(modal) {\n var wrapper = target.closest(CalendarSelectors.wrapper);\n modal.setCourseId(wrapper.data('courseid'));\n\n var categoryId = wrapper.data('categoryid');\n if (typeof categoryId !== 'undefined') {\n modal.setCategoryId(categoryId);\n }\n\n modal.setContextId(wrapper.data('contextId'));\n modal.setStartTime(startTime);\n modal.show();\n return;\n }).catch(Notification.exception);\n }\n }\n e.preventDefault();\n });\n }\n };\n\n return {\n /**\n * Initializes the calendar view manager and registers event listeners.\n *\n * @param {HTMLElement} root - The root element where the calendar view manager and event listeners will be attached.\n * @param {boolean} [isCalendarBlock=false] - A flag indicating whether this is a calendar block.\n */\n init: function(root, isCalendarBlock = false) {\n root = $(root);\n CalendarViewManager.init(root, 'month', isCalendarBlock);\n registerEventListeners(root, isCalendarBlock);\n }\n };\n});\n"],"names":["define","$","Templates","Notification","CalendarRepository","CalendarEvents","CalendarViewManager","CalendarCrud","CalendarSelectors","Url","Str","SELECTORS","handleMoveEvent","e","eventId","originElement","destinationElement","originTimestamp","destinationTimestamp","attr","render","then","html","js","find","addClass","appendNodeContents","updateEventStartDay","trigger","eventMoved","always","destinationLoadingElement","removeClass","replaceNode","originLoadingElement","catch","exception","registerEventListeners","root","isCalendarBlock","viewingFullCalendar","document","getElementById","fullCalendarView","on","dayLink","target","closest","year","data","month","day","courseId","categoryId","urlParams","view","time","course","urlParamString","Object","entries","map","_ref","key","value","encodeURIComponent","join","refreshDayContent","preventDefault","updateUrl","window","location","assign","relativeUrl","elements","courseSelector","selectElement","this","val","courseName","text","reloadCurrentMonth","handleCourseChange","Number","eventFormPromise","registerEventFormModal","contextId","eventFormModalPromise","body","created","deleted","updated","editActionEvent","url","moveEvent","monthChanged","async","monthName","monthAnnoucement","get_string","registerEditListeners","registerCalendarEventListeners","displayingSmallBlockCalendar","parents","dateContainer","wrapper","params","length","startTime","modal","setCourseId","setCategoryId","setContextId","setStartTime","show","init"],"mappings":"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"} \ No newline at end of file diff --git a/calendar/amd/build/calendar_view.min.js b/calendar/amd/build/calendar_view.min.js index ea95fe5c921..7036b14f612 100644 --- a/calendar/amd/build/calendar_view.min.js +++ b/calendar/amd/build/calendar_view.min.js @@ -5,6 +5,6 @@ * @copyright 2017 Simey Lameze * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("core_calendar/calendar_view",["jquery","core/notification","core_calendar/selectors","core_calendar/events","core_calendar/view_manager","core_calendar/crud"],(function($,Notification,CalendarSelectors,CalendarEvents,CalendarViewManager,CalendarCrud){return{init:function(root,type){root=$(root),CalendarViewManager.init(root,type),function(root,type){var body=$("body");CalendarCrud.registerRemove(root);var reloadFunction="reloadCurrent"+type.charAt(0).toUpperCase()+type.slice(1);body.on(CalendarEvents.created,(function(){CalendarViewManager[reloadFunction](root)})),body.on(CalendarEvents.deleted,(function(){CalendarViewManager[reloadFunction](root)})),body.on(CalendarEvents.updated,(function(){CalendarViewManager[reloadFunction](root)})),root.on("change",CalendarSelectors.courseSelector,(function(){var selectElement=$(this),courseId=selectElement.val();const courseName=$("option:selected",selectElement).text();CalendarViewManager[reloadFunction](root,courseId,null).then((function(){return root.find(CalendarSelectors.courseSelector).val(courseId)})).then((function(){CalendarViewManager.updateUrl("?view="+type+"&course="+courseId),CalendarViewManager.handleCourseChange(Number(courseId),courseName)})).fail(Notification.exception)})),body.on(CalendarEvents.filterChanged,(function(e,data){var daysWithEvent=root.find(CalendarSelectors.eventType[data.type]);1==data.hidden?daysWithEvent.addClass("hidden"):daysWithEvent.removeClass("hidden"),CalendarViewManager.foldDayEvents(root)}));var eventFormPromise=CalendarCrud.registerEventFormModal(root);CalendarCrud.registerEditListeners(root,eventFormPromise)}(root,type)}}})); +define("core_calendar/calendar_view",["jquery","core/notification","core_calendar/selectors","core_calendar/events","core_calendar/view_manager","core_calendar/crud"],(function($,Notification,CalendarSelectors,CalendarEvents,CalendarViewManager,CalendarCrud){var registerEventListeners=function(root,type){var body=$("body");CalendarCrud.registerRemove(root);var reloadFunction="reloadCurrent"+type.charAt(0).toUpperCase()+type.slice(1);body.on(CalendarEvents.created,(function(){CalendarViewManager[reloadFunction](root)})),body.on(CalendarEvents.deleted,(function(){CalendarViewManager[reloadFunction](root)})),body.on(CalendarEvents.updated,(function(){CalendarViewManager[reloadFunction](root)})),root.on("change",CalendarSelectors.courseSelector,(function(){var selectElement=$(this),courseId=selectElement.val();const courseName=$("option:selected",selectElement).text();CalendarViewManager[reloadFunction](root,courseId,null).then((function(){return root.find(CalendarSelectors.courseSelector).val(courseId)})).then((function(){CalendarViewManager.updateUrl("?view="+type+"&course="+courseId),CalendarViewManager.handleCourseChange(Number(courseId),courseName)})).fail(Notification.exception)})),body.on(CalendarEvents.filterChanged,(function(e,data){var daysWithEvent=root.find(CalendarSelectors.eventType[data.type]);1==data.hidden?daysWithEvent.addClass("hidden"):daysWithEvent.removeClass("hidden"),CalendarViewManager.foldDayEvents(root)}));var eventFormPromise=CalendarCrud.registerEventFormModal(root);CalendarCrud.registerEditListeners(root,eventFormPromise)};return{init:function(root,type){let isCalendarBlock=arguments.length>2&&void 0!==arguments[2]&&arguments[2];root=$(root),CalendarViewManager.init(root,type,isCalendarBlock),registerEventListeners(root,type)}}})); //# sourceMappingURL=calendar_view.min.js.map \ No newline at end of file diff --git a/calendar/amd/build/calendar_view.min.js.map b/calendar/amd/build/calendar_view.min.js.map index 62d6024ba40..ff5df73ff6b 100644 --- a/calendar/amd/build/calendar_view.min.js.map +++ b/calendar/amd/build/calendar_view.min.js.map @@ -1 +1 @@ -{"version":3,"file":"calendar_view.min.js","sources":["../src/calendar_view.js"],"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 * This module is responsible for handle calendar day and upcoming view.\n *\n * @module core_calendar/calendar_view\n * @copyright 2017 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/notification',\n 'core_calendar/selectors',\n 'core_calendar/events',\n 'core_calendar/view_manager',\n 'core_calendar/crud'\n],\nfunction(\n $,\n Notification,\n CalendarSelectors,\n CalendarEvents,\n CalendarViewManager,\n CalendarCrud\n) {\n\n var registerEventListeners = function(root, type) {\n var body = $('body');\n\n CalendarCrud.registerRemove(root);\n\n var reloadFunction = 'reloadCurrent' + type.charAt(0).toUpperCase() + type.slice(1);\n\n body.on(CalendarEvents.created, function() {\n CalendarViewManager[reloadFunction](root);\n });\n body.on(CalendarEvents.deleted, function() {\n CalendarViewManager[reloadFunction](root);\n });\n body.on(CalendarEvents.updated, function() {\n CalendarViewManager[reloadFunction](root);\n });\n\n root.on('change', CalendarSelectors.courseSelector, function() {\n var selectElement = $(this);\n var courseId = selectElement.val();\n const courseName = $(\"option:selected\", selectElement).text();\n CalendarViewManager[reloadFunction](root, courseId, null)\n .then(function() {\n // We need to get the selector again because the content has changed.\n return root.find(CalendarSelectors.courseSelector).val(courseId);\n })\n .then(function() {\n CalendarViewManager.updateUrl('?view=' + type + '&course=' + courseId);\n CalendarViewManager.handleCourseChange(Number(courseId), courseName);\n return;\n })\n .fail(Notification.exception);\n });\n\n body.on(CalendarEvents.filterChanged, function(e, data) {\n var daysWithEvent = root.find(CalendarSelectors.eventType[data.type]);\n if (data.hidden == true) {\n daysWithEvent.addClass('hidden');\n } else {\n daysWithEvent.removeClass('hidden');\n }\n CalendarViewManager.foldDayEvents(root);\n });\n\n var eventFormPromise = CalendarCrud.registerEventFormModal(root);\n CalendarCrud.registerEditListeners(root, eventFormPromise);\n };\n\n return {\n init: function(root, type) {\n root = $(root);\n\n CalendarViewManager.init(root, type);\n registerEventListeners(root, type);\n }\n };\n });\n"],"names":["define","$","Notification","CalendarSelectors","CalendarEvents","CalendarViewManager","CalendarCrud","init","root","type","body","registerRemove","reloadFunction","charAt","toUpperCase","slice","on","created","deleted","updated","courseSelector","selectElement","this","courseId","val","courseName","text","then","find","updateUrl","handleCourseChange","Number","fail","exception","filterChanged","e","data","daysWithEvent","eventType","hidden","addClass","removeClass","foldDayEvents","eventFormPromise","registerEventFormModal","registerEditListeners","registerEventListeners"],"mappings":";;;;;;;AAsBAA,qCAAO,CACH,SACA,oBACA,0BACA,uBACA,6BACA,uBAEJ,SACIC,EACAC,aACAC,kBACAC,eACAC,oBACAC,oBAmDW,CACHC,KAAM,SAASC,KAAMC,MACjBD,KAAOP,EAAEO,MAETH,oBAAoBE,KAAKC,KAAMC,MApDV,SAASD,KAAMC,UACpCC,KAAOT,EAAE,QAEbK,aAAaK,eAAeH,UAExBI,eAAiB,gBAAkBH,KAAKI,OAAO,GAAGC,cAAgBL,KAAKM,MAAM,GAEjFL,KAAKM,GAAGZ,eAAea,SAAS,WAC5BZ,oBAAoBO,gBAAgBJ,SAExCE,KAAKM,GAAGZ,eAAec,SAAS,WAC5Bb,oBAAoBO,gBAAgBJ,SAExCE,KAAKM,GAAGZ,eAAee,SAAS,WAC5Bd,oBAAoBO,gBAAgBJ,SAGxCA,KAAKQ,GAAG,SAAUb,kBAAkBiB,gBAAgB,eAC5CC,cAAgBpB,EAAEqB,MAClBC,SAAWF,cAAcG,YACvBC,WAAaxB,EAAE,kBAAmBoB,eAAeK,OACvDrB,oBAAoBO,gBAAgBJ,KAAMe,SAAU,MAC/CI,MAAK,kBAEKnB,KAAKoB,KAAKzB,kBAAkBiB,gBAAgBI,IAAID,aAE1DI,MAAK,WACFtB,oBAAoBwB,UAAU,SAAWpB,KAAO,WAAac,UAC7DlB,oBAAoByB,mBAAmBC,OAAOR,UAAWE,eAG5DO,KAAK9B,aAAa+B,cAG3BvB,KAAKM,GAAGZ,eAAe8B,eAAe,SAASC,EAAGC,UAC1CC,cAAgB7B,KAAKoB,KAAKzB,kBAAkBmC,UAAUF,KAAK3B,OAC5C,GAAf2B,KAAKG,OACLF,cAAcG,SAAS,UAEvBH,cAAcI,YAAY,UAE9BpC,oBAAoBqC,cAAclC,aAGlCmC,iBAAmBrC,aAAasC,uBAAuBpC,MAC3DF,aAAauC,sBAAsBrC,KAAMmC,kBAQrCG,CAAuBtC,KAAMC"} \ No newline at end of file +{"version":3,"file":"calendar_view.min.js","sources":["../src/calendar_view.js"],"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 * This module is responsible for handle calendar day and upcoming view.\n *\n * @module core_calendar/calendar_view\n * @copyright 2017 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/notification',\n 'core_calendar/selectors',\n 'core_calendar/events',\n 'core_calendar/view_manager',\n 'core_calendar/crud'\n],\nfunction(\n $,\n Notification,\n CalendarSelectors,\n CalendarEvents,\n CalendarViewManager,\n CalendarCrud\n) {\n\n var registerEventListeners = function(root, type) {\n var body = $('body');\n\n CalendarCrud.registerRemove(root);\n\n var reloadFunction = 'reloadCurrent' + type.charAt(0).toUpperCase() + type.slice(1);\n\n body.on(CalendarEvents.created, function() {\n CalendarViewManager[reloadFunction](root);\n });\n body.on(CalendarEvents.deleted, function() {\n CalendarViewManager[reloadFunction](root);\n });\n body.on(CalendarEvents.updated, function() {\n CalendarViewManager[reloadFunction](root);\n });\n\n root.on('change', CalendarSelectors.courseSelector, function() {\n var selectElement = $(this);\n var courseId = selectElement.val();\n const courseName = $(\"option:selected\", selectElement).text();\n CalendarViewManager[reloadFunction](root, courseId, null)\n .then(function() {\n // We need to get the selector again because the content has changed.\n return root.find(CalendarSelectors.courseSelector).val(courseId);\n })\n .then(function() {\n CalendarViewManager.updateUrl('?view=' + type + '&course=' + courseId);\n CalendarViewManager.handleCourseChange(Number(courseId), courseName);\n return;\n })\n .fail(Notification.exception);\n });\n\n body.on(CalendarEvents.filterChanged, function(e, data) {\n var daysWithEvent = root.find(CalendarSelectors.eventType[data.type]);\n if (data.hidden == true) {\n daysWithEvent.addClass('hidden');\n } else {\n daysWithEvent.removeClass('hidden');\n }\n CalendarViewManager.foldDayEvents(root);\n });\n\n var eventFormPromise = CalendarCrud.registerEventFormModal(root);\n CalendarCrud.registerEditListeners(root, eventFormPromise);\n };\n\n return {\n init: function(root, type, isCalendarBlock = false) {\n root = $(root);\n\n CalendarViewManager.init(root, type, isCalendarBlock);\n registerEventListeners(root, type, isCalendarBlock);\n }\n };\n });\n"],"names":["define","$","Notification","CalendarSelectors","CalendarEvents","CalendarViewManager","CalendarCrud","registerEventListeners","root","type","body","registerRemove","reloadFunction","charAt","toUpperCase","slice","on","created","deleted","updated","courseSelector","selectElement","this","courseId","val","courseName","text","then","find","updateUrl","handleCourseChange","Number","fail","exception","filterChanged","e","data","daysWithEvent","eventType","hidden","addClass","removeClass","foldDayEvents","eventFormPromise","registerEventFormModal","registerEditListeners","init","isCalendarBlock"],"mappings":";;;;;;;AAsBAA,qCAAO,CACH,SACA,oBACA,0BACA,uBACA,6BACA,uBAEJ,SACIC,EACAC,aACAC,kBACAC,eACAC,oBACAC,kBAGQC,uBAAyB,SAASC,KAAMC,UACpCC,KAAOT,EAAE,QAEbK,aAAaK,eAAeH,UAExBI,eAAiB,gBAAkBH,KAAKI,OAAO,GAAGC,cAAgBL,KAAKM,MAAM,GAEjFL,KAAKM,GAAGZ,eAAea,SAAS,WAC5BZ,oBAAoBO,gBAAgBJ,SAExCE,KAAKM,GAAGZ,eAAec,SAAS,WAC5Bb,oBAAoBO,gBAAgBJ,SAExCE,KAAKM,GAAGZ,eAAee,SAAS,WAC5Bd,oBAAoBO,gBAAgBJ,SAGxCA,KAAKQ,GAAG,SAAUb,kBAAkBiB,gBAAgB,eAC5CC,cAAgBpB,EAAEqB,MAClBC,SAAWF,cAAcG,YACvBC,WAAaxB,EAAE,kBAAmBoB,eAAeK,OACvDrB,oBAAoBO,gBAAgBJ,KAAMe,SAAU,MAC/CI,MAAK,kBAEKnB,KAAKoB,KAAKzB,kBAAkBiB,gBAAgBI,IAAID,aAE1DI,MAAK,WACFtB,oBAAoBwB,UAAU,SAAWpB,KAAO,WAAac,UAC7DlB,oBAAoByB,mBAAmBC,OAAOR,UAAWE,eAG5DO,KAAK9B,aAAa+B,cAG3BvB,KAAKM,GAAGZ,eAAe8B,eAAe,SAASC,EAAGC,UAC1CC,cAAgB7B,KAAKoB,KAAKzB,kBAAkBmC,UAAUF,KAAK3B,OAC5C,GAAf2B,KAAKG,OACLF,cAAcG,SAAS,UAEvBH,cAAcI,YAAY,UAE9BpC,oBAAoBqC,cAAclC,aAGlCmC,iBAAmBrC,aAAasC,uBAAuBpC,MAC3DF,aAAauC,sBAAsBrC,KAAMmC,yBAGtC,CACHG,KAAM,SAAStC,KAAMC,UAAMsC,wEACvBvC,KAAOP,EAAEO,MAETH,oBAAoByC,KAAKtC,KAAMC,KAAMsC,iBACrCxC,uBAAuBC,KAAMC"} \ No newline at end of file diff --git a/calendar/amd/build/popover.min.js b/calendar/amd/build/popover.min.js index e7c42111597..a7a5bf451fe 100644 --- a/calendar/amd/build/popover.min.js +++ b/calendar/amd/build/popover.min.js @@ -6,6 +6,6 @@ define("core_calendar/popover",["theme_boost/popover","jquery","core_calendar/se * @copyright 2021 Huong Nguyen * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since 4.0 - */function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj},CalendarSelectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(CalendarSelectors);const isPopoverConfigured=new Map,showPopover=target=>{const dateContainer=target.closest(CalendarSelectors.elements.dateContainer);if(!isPopoverConfigured.has(dateContainer)){(0,_jquery.default)(target).popover({trigger:"manual",placement:"top",html:!0,title:dateContainer.dataset.title,content:()=>{const source=(0,_jquery.default)(dateContainer).find(CalendarSelectors.elements.dateContent),content=(0,_jquery.default)("
");if(source.length){const temptContent=source.find(".hidden").clone(!1);content.html(temptContent.html())}return content.html()}}),isPopoverConfigured.set(dateContainer,!0)}(dateContainer=>"none"===window.getComputedStyle(dateContainer.querySelector(CalendarSelectors.elements.dateContent)).display)(dateContainer)&&((0,_jquery.default)(target).popover("show"),target.addEventListener("mouseleave",hidePopover),target.addEventListener("focusout",hidePopover))},hidePopover=e=>{const target=e.target,dateContainer=e.target.closest(CalendarSelectors.elements.dateContainer);if(dateContainer&&isPopoverConfigured.has(dateContainer)){const isTargetActive=target.contains(document.activeElement),isTargetHover=target.matches(":hover");isTargetActive||isTargetHover||((0,_jquery.default)(target).popover("hide"),target.removeEventListener("mouseleave",hidePopover),target.removeEventListener("focusout",hidePopover))}};let listenersRegistered=!1;listenersRegistered||((()=>{const showPopoverHandler=e=>{const dayLink=e.target.closest(CalendarSelectors.links.dayLink);dayLink&&(e.preventDefault(),showPopover(dayLink))};document.addEventListener("mouseover",showPopoverHandler),document.addEventListener("focusin",showPopoverHandler)})(),listenersRegistered=!0)})); + */function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj},CalendarSelectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(CalendarSelectors);const isPopoverConfigured=new Map,showPopover=target=>{const dateContainer=target.closest(CalendarSelectors.elements.dateContainer);if(!isPopoverConfigured.has(dateContainer)){(0,_jquery.default)(target).popover({trigger:"manual",placement:"top",html:!0,title:dateContainer.dataset.title,content:()=>{const source=(0,_jquery.default)(dateContainer).find(CalendarSelectors.elements.dateContent),content=(0,_jquery.default)("
");if(source.length){const temptContent=source.find(".hidden").clone(!1);content.html(temptContent.html())}return content.html()},animation:!1}),isPopoverConfigured.set(dateContainer,!0)}(dateContainer=>"none"===window.getComputedStyle(dateContainer.querySelector(CalendarSelectors.elements.dateContent)).display)(dateContainer)&&((0,_jquery.default)(target).popover("show"),target.addEventListener("mouseleave",hidePopover),target.addEventListener("focusout",hidePopover),target.addEventListener("click",hidePopover))},hidePopover=e=>{const target=e.target,dateContainer=e.target.closest(CalendarSelectors.elements.dateContainer);if(dateContainer&&isPopoverConfigured.has(dateContainer)){const isTargetActive=target.contains(document.activeElement),isTargetHover=target.matches(":hover"),isTargetClicked=document.activeElement.contains(target);let removeListener=!0;isTargetActive||isTargetHover?isTargetClicked?(0,_jquery.default)(document.activeElement).popover("hide"):removeListener=!1:(0,_jquery.default)(target).popover("hide"),removeListener&&(target.removeEventListener("mouseleave",hidePopover),target.removeEventListener("focusout",hidePopover),target.removeEventListener("click",hidePopover))}};let listenersRegistered=!1;listenersRegistered||((()=>{const showPopoverHandler=e=>{const dayLink=e.target.closest(CalendarSelectors.links.dayLink);dayLink&&(e.preventDefault(),showPopover(dayLink))};document.addEventListener("mouseover",showPopoverHandler),document.addEventListener("focusin",showPopoverHandler)})(),listenersRegistered=!0)})); //# sourceMappingURL=popover.min.js.map \ No newline at end of file diff --git a/calendar/amd/build/popover.min.js.map b/calendar/amd/build/popover.min.js.map index abf62598844..1d406bf8da5 100644 --- a/calendar/amd/build/popover.min.js.map +++ b/calendar/amd/build/popover.min.js.map @@ -1 +1 @@ -{"version":3,"file":"popover.min.js","sources":["../src/popover.js"],"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 * Javascript popover for the `core_calendar` subsystem.\n *\n * @module core_calendar/popover\n * @copyright 2021 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n */\n\nimport 'theme_boost/popover';\nimport jQuery from 'jquery';\nimport * as CalendarSelectors from 'core_calendar/selectors';\n\n/**\n * Check if we are allowing to enable the popover or not.\n * @param {Element} dateContainer\n * @returns {boolean}\n */\nconst isPopoverAvailable = (dateContainer) => {\n return window.getComputedStyle(dateContainer.querySelector(CalendarSelectors.elements.dateContent)).display === 'none';\n};\n\nconst isPopoverConfigured = new Map();\n\nconst showPopover = target => {\n const dateContainer = target.closest(CalendarSelectors.elements.dateContainer);\n if (!isPopoverConfigured.has(dateContainer)) {\n const dateEle = jQuery(target);\n dateEle.popover({\n trigger: 'manual',\n placement: 'top',\n html: true,\n title: dateContainer.dataset.title,\n content: () => {\n const source = jQuery(dateContainer).find(CalendarSelectors.elements.dateContent);\n const content = jQuery('
');\n if (source.length) {\n const temptContent = source.find('.hidden').clone(false);\n content.html(temptContent.html());\n }\n return content.html();\n }\n });\n\n isPopoverConfigured.set(dateContainer, true);\n }\n\n if (isPopoverAvailable(dateContainer)) {\n jQuery(target).popover('show');\n target.addEventListener('mouseleave', hidePopover);\n target.addEventListener('focusout', hidePopover);\n }\n};\n\nconst hidePopover = e => {\n const target = e.target;\n const dateContainer = e.target.closest(CalendarSelectors.elements.dateContainer);\n if (!dateContainer) {\n return;\n }\n if (isPopoverConfigured.has(dateContainer)) {\n const isTargetActive = target.contains(document.activeElement);\n const isTargetHover = target.matches(':hover');\n if (!isTargetActive && !isTargetHover) {\n jQuery(target).popover('hide');\n target.removeEventListener('mouseleave', hidePopover);\n target.removeEventListener('focusout', hidePopover);\n }\n }\n};\n\n/**\n * Register events for date container.\n */\nconst registerEventListeners = () => {\n const showPopoverHandler = (e) => {\n const dayLink = e.target.closest(CalendarSelectors.links.dayLink);\n if (!dayLink) {\n return;\n }\n\n e.preventDefault();\n showPopover(dayLink);\n };\n\n document.addEventListener('mouseover', showPopoverHandler);\n document.addEventListener('focusin', showPopoverHandler);\n};\n\nlet listenersRegistered = false;\nif (!listenersRegistered) {\n registerEventListeners();\n listenersRegistered = true;\n}\n"],"names":["isPopoverConfigured","Map","showPopover","target","dateContainer","closest","CalendarSelectors","elements","has","popover","trigger","placement","html","title","dataset","content","source","find","dateContent","length","temptContent","clone","set","window","getComputedStyle","querySelector","display","isPopoverAvailable","addEventListener","hidePopover","e","isTargetActive","contains","document","activeElement","isTargetHover","matches","removeEventListener","listenersRegistered","showPopoverHandler","dayLink","links","preventDefault","registerEventListeners"],"mappings":";;;;;;;;wgCAqCMA,oBAAsB,IAAIC,IAE1BC,YAAcC,eACVC,cAAgBD,OAAOE,QAAQC,kBAAkBC,SAASH,mBAC3DJ,oBAAoBQ,IAAIJ,eAAgB,EACzB,mBAAOD,QACfM,QAAQ,CACZC,QAAS,SACTC,UAAW,MACXC,MAAM,EACNC,MAAOT,cAAcU,QAAQD,MAC7BE,QAAS,WACCC,QAAS,mBAAOZ,eAAea,KAAKX,kBAAkBC,SAASW,aAC/DH,SAAU,mBAAO,YACnBC,OAAOG,OAAQ,OACTC,aAAeJ,OAAOC,KAAK,WAAWI,OAAM,GAClDN,QAAQH,KAAKQ,aAAaR,eAEvBG,QAAQH,UAIvBZ,oBAAoBsB,IAAIlB,eAAe,GA1BnBA,CAAAA,eACwF,SAAzGmB,OAAOC,iBAAiBpB,cAAcqB,cAAcnB,kBAAkBC,SAASW,cAAcQ,QA4BhGC,CAAmBvB,qCACZD,QAAQM,QAAQ,QACvBN,OAAOyB,iBAAiB,aAAcC,aACtC1B,OAAOyB,iBAAiB,WAAYC,eAItCA,YAAcC,UACV3B,OAAS2B,EAAE3B,OACXC,cAAgB0B,EAAE3B,OAAOE,QAAQC,kBAAkBC,SAASH,kBAC7DA,eAGDJ,oBAAoBQ,IAAIJ,eAAgB,OAClC2B,eAAiB5B,OAAO6B,SAASC,SAASC,eAC1CC,cAAgBhC,OAAOiC,QAAQ,UAChCL,gBAAmBI,oCACbhC,QAAQM,QAAQ,QACvBN,OAAOkC,oBAAoB,aAAcR,aACzC1B,OAAOkC,oBAAoB,WAAYR,oBAuB/CS,qBAAsB,EACrBA,sBAhB0B,YACrBC,mBAAsBT,UAClBU,QAAUV,EAAE3B,OAAOE,QAAQC,kBAAkBmC,MAAMD,SACpDA,UAILV,EAAEY,iBACFxC,YAAYsC,WAGhBP,SAASL,iBAAiB,YAAaW,oBACvCN,SAASL,iBAAiB,UAAWW,qBAKrCI,GACAL,qBAAsB"} \ No newline at end of file +{"version":3,"file":"popover.min.js","sources":["../src/popover.js"],"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 * Javascript popover for the `core_calendar` subsystem.\n *\n * @module core_calendar/popover\n * @copyright 2021 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n */\n\nimport 'theme_boost/popover';\nimport jQuery from 'jquery';\nimport * as CalendarSelectors from 'core_calendar/selectors';\n\n/**\n * Check if we are allowing to enable the popover or not.\n * @param {Element} dateContainer\n * @returns {boolean}\n */\nconst isPopoverAvailable = (dateContainer) => {\n return window.getComputedStyle(dateContainer.querySelector(CalendarSelectors.elements.dateContent)).display === 'none';\n};\n\nconst isPopoverConfigured = new Map();\n\nconst showPopover = target => {\n const dateContainer = target.closest(CalendarSelectors.elements.dateContainer);\n if (!isPopoverConfigured.has(dateContainer)) {\n const dateEle = jQuery(target);\n dateEle.popover({\n trigger: 'manual',\n placement: 'top',\n html: true,\n title: dateContainer.dataset.title,\n content: () => {\n const source = jQuery(dateContainer).find(CalendarSelectors.elements.dateContent);\n const content = jQuery('
');\n if (source.length) {\n const temptContent = source.find('.hidden').clone(false);\n content.html(temptContent.html());\n }\n return content.html();\n },\n 'animation': false,\n });\n\n isPopoverConfigured.set(dateContainer, true);\n }\n\n if (isPopoverAvailable(dateContainer)) {\n jQuery(target).popover('show');\n target.addEventListener('mouseleave', hidePopover);\n target.addEventListener('focusout', hidePopover);\n // Set up the hide function to the click event type.\n target.addEventListener('click', hidePopover);\n }\n};\n\nconst hidePopover = e => {\n const target = e.target;\n const dateContainer = e.target.closest(CalendarSelectors.elements.dateContainer);\n if (!dateContainer) {\n return;\n }\n if (isPopoverConfigured.has(dateContainer)) {\n const isTargetActive = target.contains(document.activeElement);\n const isTargetHover = target.matches(':hover');\n\n // Checks if a target element is clicked or pressed.\n const isTargetClicked = document.activeElement.contains(target);\n\n let removeListener = true;\n if (!isTargetActive && !isTargetHover) {\n jQuery(target).popover('hide');\n } else if (isTargetClicked) {\n jQuery(document.activeElement).popover('hide');\n } else {\n removeListener = false;\n }\n\n if (removeListener) {\n target.removeEventListener('mouseleave', hidePopover);\n target.removeEventListener('focusout', hidePopover);\n target.removeEventListener('click', hidePopover);\n }\n }\n};\n\n/**\n * Register events for date container.\n */\nconst registerEventListeners = () => {\n const showPopoverHandler = (e) => {\n const dayLink = e.target.closest(CalendarSelectors.links.dayLink);\n if (!dayLink) {\n return;\n }\n\n e.preventDefault();\n showPopover(dayLink);\n };\n\n document.addEventListener('mouseover', showPopoverHandler);\n document.addEventListener('focusin', showPopoverHandler);\n};\n\nlet listenersRegistered = false;\nif (!listenersRegistered) {\n registerEventListeners();\n listenersRegistered = true;\n}\n"],"names":["isPopoverConfigured","Map","showPopover","target","dateContainer","closest","CalendarSelectors","elements","has","popover","trigger","placement","html","title","dataset","content","source","find","dateContent","length","temptContent","clone","set","window","getComputedStyle","querySelector","display","isPopoverAvailable","addEventListener","hidePopover","e","isTargetActive","contains","document","activeElement","isTargetHover","matches","isTargetClicked","removeListener","removeEventListener","listenersRegistered","showPopoverHandler","dayLink","links","preventDefault","registerEventListeners"],"mappings":";;;;;;;;wgCAqCMA,oBAAsB,IAAIC,IAE1BC,YAAcC,eACVC,cAAgBD,OAAOE,QAAQC,kBAAkBC,SAASH,mBAC3DJ,oBAAoBQ,IAAIJ,eAAgB,EACzB,mBAAOD,QACfM,QAAQ,CACZC,QAAS,SACTC,UAAW,MACXC,MAAM,EACNC,MAAOT,cAAcU,QAAQD,MAC7BE,QAAS,WACCC,QAAS,mBAAOZ,eAAea,KAAKX,kBAAkBC,SAASW,aAC/DH,SAAU,mBAAO,YACnBC,OAAOG,OAAQ,OACTC,aAAeJ,OAAOC,KAAK,WAAWI,OAAM,GAClDN,QAAQH,KAAKQ,aAAaR,eAEvBG,QAAQH,mBAEN,IAGjBZ,oBAAoBsB,IAAIlB,eAAe,GA3BnBA,CAAAA,eACwF,SAAzGmB,OAAOC,iBAAiBpB,cAAcqB,cAAcnB,kBAAkBC,SAASW,cAAcQ,QA6BhGC,CAAmBvB,qCACZD,QAAQM,QAAQ,QACvBN,OAAOyB,iBAAiB,aAAcC,aACtC1B,OAAOyB,iBAAiB,WAAYC,aAEpC1B,OAAOyB,iBAAiB,QAASC,eAInCA,YAAcC,UACV3B,OAAS2B,EAAE3B,OACXC,cAAgB0B,EAAE3B,OAAOE,QAAQC,kBAAkBC,SAASH,kBAC7DA,eAGDJ,oBAAoBQ,IAAIJ,eAAgB,OAClC2B,eAAiB5B,OAAO6B,SAASC,SAASC,eAC1CC,cAAgBhC,OAAOiC,QAAQ,UAG/BC,gBAAkBJ,SAASC,cAAcF,SAAS7B,YAEpDmC,gBAAiB,EAChBP,gBAAmBI,cAEbE,oCACAJ,SAASC,eAAezB,QAAQ,QAEvC6B,gBAAiB,sBAJVnC,QAAQM,QAAQ,QAOvB6B,iBACAnC,OAAOoC,oBAAoB,aAAcV,aACzC1B,OAAOoC,oBAAoB,WAAYV,aACvC1B,OAAOoC,oBAAoB,QAASV,oBAuB5CW,qBAAsB,EACrBA,sBAhB0B,YACrBC,mBAAsBX,UAClBY,QAAUZ,EAAE3B,OAAOE,QAAQC,kBAAkBqC,MAAMD,SACpDA,UAILZ,EAAEc,iBACF1C,YAAYwC,WAGhBT,SAASL,iBAAiB,YAAaa,oBACvCR,SAASL,iBAAiB,UAAWa,qBAKrCI,GACAL,qBAAsB"} \ 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 10e3eab5f11..f7f4660c298 100644 --- a/calendar/amd/build/view_manager.min.js +++ b/calendar/amd/build/view_manager.min.js @@ -5,6 +5,6 @@ define("core_calendar/view_manager",["exports","jquery","core/templates","core/n * @module core_calendar/view_manager * @copyright 2017 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.updateUrl=_exports.reloadCurrentUpcoming=_exports.reloadCurrentMonth=_exports.reloadCurrentDay=_exports.registerEventListenersForMonthDetailed=_exports.refreshMonthContent=_exports.refreshDayContent=_exports.init=_exports.handleCourseChange=_exports.foldDayEvents=_exports.changeMonth=_exports.changeDay=void 0,_jquery=_interopRequireDefault(_jquery),_templates=_interopRequireDefault(_templates),_notification=_interopRequireDefault(_notification),CalendarRepository=_interopRequireWildcard(CalendarRepository),_events=_interopRequireDefault(_events),CalendarSelectors=_interopRequireWildcard(CalendarSelectors),_modal_events=_interopRequireDefault(_modal_events),_summary_modal=_interopRequireDefault(_summary_modal),_custom_interaction_events=_interopRequireDefault(_custom_interaction_events),_pending=_interopRequireDefault(_pending),_url=_interopRequireDefault(_url),_config=_interopRequireDefault(_config);const foldDayEvents=()=>{const days=(0,_jquery.default)(CalendarSelectors.elements.monthDetailed).find(CalendarSelectors.day);0!==days.length&&days.each((function(){const dayContainer=(0,_jquery.default)(this),eventsSelector="".concat(CalendarSelectors.elements.dateContent," ul li[data-event-eventtype]"),filteredEventsSelector="".concat(CalendarSelectors.elements.dateContent,' ul li[data-event-filtered="true"]'),moreEventsSelector="".concat(CalendarSelectors.elements.dateContent,' [data-action="view-more-events"]'),events=dayContainer.find(eventsSelector);if(0===events.length)return;const numberOfFiltered=dayContainer.find(filteredEventsSelector).length,numberOfEvents=events.length-numberOfFiltered;let count=1;events.each((function(){const event=(0,_jquery.default)(this);"true"!==event.attr("data-event-filtered")?count>5-(5===numberOfEvents?0:1)?(event.attr("data-event-folded","true"),event.hide()):(event.attr("data-event-folded","false"),event.show(),count++):event.attr("data-event-folded","false")}));const moreEventsLink=dayContainer.find(moreEventsSelector);if(numberOfEvents>5){const numberOfHiddenEvents=numberOfEvents-5+1;moreEventsLink.show(),(0,_str.getString)("moreevents","calendar",numberOfHiddenEvents).then((str=>{const link=moreEventsLink.find("strong a");return moreEventsLink.attr("data-event-folded","false"),link.text(str),str})).catch(_notification.default.exception)}else moreEventsLink.hide()}))};_exports.foldDayEvents=foldDayEvents;const registerEventListenersForMonthDetailed=pendingId=>{const events="".concat(_events.default.viewUpdated);(0,_jquery.default)("body").on(events,(function(e){foldDayEvents()})),foldDayEvents(),(0,_jquery.default)("body").on(_events.default.filterChanged,(function(e,data){const root=(0,_jquery.default)(CalendarSelectors.elements.monthDetailed),pending=new _pending.default(pendingId),target=root.find(CalendarSelectors.eventType[data.type]),transitionPromise=_jquery.default.Deferred();data.hidden?transitionPromise.then((function(){return target.attr("data-event-filtered","true"),target.hide().promise()})).fail():transitionPromise.then((function(){return target.attr("data-event-filtered","false"),target.show().promise()})).fail(),transitionPromise.then((function(){foldDayEvents()})).always(pending.resolve).fail(),transitionPromise.resolve()}))};_exports.registerEventListenersForMonthDetailed=registerEventListenersForMonthDetailed;const refreshMonthContent=function(root,year,month,courseId,categoryId){let target=arguments.length>5&&void 0!==arguments[5]?arguments[5]:null,template=arguments.length>6&&void 0!==arguments[6]?arguments[6]:"",day=arguments.length>7&&void 0!==arguments[7]?arguments[7]: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"),mini=root.data("mini"),viewMode=target.data("view");return CalendarRepository.getCalendarMonthData(year,month,courseId,categoryId,includenavigation,mini,day,viewMode).then((context=>_templates.default.render(template,context))).then(((html,js)=>_templates.default.replaceNode(target,html,js))).then((()=>{document.querySelector("body").dispatchEvent(new CustomEvent(_events.default.viewUpdated))})).always((()=>(M.util.js_complete([root.get("id"),year,month,courseId].join("-")),stopLoading(root)))).fail(_notification.default.exception)};_exports.refreshMonthContent=refreshMonthContent;const changeMonth=function(root,url,year,month,courseId,categoryId){let day=arguments.length>6&&void 0!==arguments[6]?arguments[6]:1;return refreshMonthContent(root,year,month,courseId,categoryId,null,"",day).then((function(){url.length&&"#"!==url&&updateUrl(url);for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++)args[_key]=arguments[_key];return args})).then((function(){(0,_jquery.default)("body").trigger(_events.default.monthChanged,[year,month,courseId,categoryId]);for(var _len2=arguments.length,args=new Array(_len2),_key2=0;_key2<_len2;_key2++)args[_key2]=arguments[_key2];return args}))};_exports.changeMonth=changeMonth;_exports.reloadCurrentMonth=function(root){let courseId=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,categoryId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;const year=root.find(CalendarSelectors.wrapper).data("year"),month=root.find(CalendarSelectors.wrapper).data("month"),day=root.find(CalendarSelectors.wrapper).data("day");return courseId=courseId||root.find(CalendarSelectors.wrapper).data("courseid"),categoryId=categoryId||root.find(CalendarSelectors.wrapper).data("categoryid"),refreshMonthContent(root,year,month,courseId,categoryId,null,"",day).then((function(){(0,_jquery.default)("body").trigger(_events.default.courseChanged,[year,month,courseId,categoryId]);for(var _len3=arguments.length,args=new Array(_len3),_key3=0;_key3<_len3;_key3++)args[_key3]=arguments[_key3];return args}))};const refreshDayContent=function(root,year,month,day,courseId,categoryId){let target=arguments.length>6&&void 0!==arguments[6]?arguments[6]:null,template=arguments.length>7&&void 0!==arguments[7]?arguments[7]:"";startLoading(root),target&&0!=target.length||(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=!0,context.showviewselector=!0,_templates.default.render(template,context)))).then(((html,js)=>_templates.default.replaceNode(target,html,js))).then((()=>{document.querySelector("body").dispatchEvent(new CustomEvent(_events.default.viewUpdated))})).always((()=>(M.util.js_complete([root.get("id"),year,month,day,courseId,categoryId].join("-")),stopLoading(root)))).fail(_notification.default.exception)};_exports.refreshDayContent=refreshDayContent;_exports.reloadCurrentDay=function(root){let courseId=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,categoryId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;const wrapper=root.find(CalendarSelectors.wrapper),year=wrapper.data("year"),month=wrapper.data("month"),day=wrapper.data("day");return courseId=courseId||root.find(CalendarSelectors.wrapper).data("courseid"),categoryId=categoryId||root.find(CalendarSelectors.wrapper).data("categoryid"),refreshDayContent(root,year,month,day,courseId,categoryId)};const changeDay=(root,url,year,month,day,courseId,categoryId)=>refreshDayContent(root,year,month,day,courseId,categoryId).then((function(){url.length&&"#"!==url&&updateUrl(url);for(var _len4=arguments.length,args=new Array(_len4),_key4=0;_key4<_len4;_key4++)args[_key4]=arguments[_key4];return args})).then((function(){(0,_jquery.default)("body").trigger(_events.default.dayChanged,[year,month,courseId,categoryId]);for(var _len5=arguments.length,args=new Array(_len5),_key5=0;_key5<_len5;_key5++)args[_key5]=arguments[_key5];return args}));_exports.changeDay=changeDay;const updateUrl=url=>{document.getElementById(CalendarSelectors.fullCalendarView)&&window.history.pushState({},"",url)};_exports.updateUrl=updateUrl;const startLoading=root=>{root.find(CalendarSelectors.containers.loadingIcon).removeClass("hidden")},stopLoading=root=>{root.find(CalendarSelectors.containers.loadingIcon).addClass("hidden")},reloadCurrentUpcoming=function(root){let courseId=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,categoryId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,target=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,template=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"";return 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"),CalendarRepository.getCalendarUpcomingData(courseId,categoryId).then((context=>(context.viewingupcoming=!0,context.showviewselector=!0,_templates.default.render(template,context)))).then(((html,js)=>_templates.default.replaceNode(target,html,js))).then((()=>{document.querySelector("body").dispatchEvent(new CustomEvent(_events.default.viewUpdated))})).always((function(){return stopLoading(root)})).fail(_notification.default.exception)};_exports.reloadCurrentUpcoming=reloadCurrentUpcoming;const renderEventSummaryModal=eventId=>{const pendingPromise=new _pending.default("core_calendar/view_manager:renderEventSummaryModal");return CalendarRepository.getEventById(eventId).then((getEventResponse=>{if(!getEventResponse.event)throw new Error("Error encountered while trying to fetch calendar event with ID: "+eventId);return getEventResponse.event})).then((eventData=>{const modalParams={title:eventData.name,body:_templates.default.render("core_calendar/event_summary_body",eventData),templateContext:{canedit:eventData.canedit,candelete:eventData.candelete,headerclasses:(eventType=eventData.normalisedeventtype,"calendar_event_"+eventType),isactionevent:eventData.isactionevent,url:eventData.url,action:eventData.action}};var eventType;return _summary_modal.default.create(modalParams)})).then((modal=>(modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show(),modal))).then((modal=>(pendingPromise.resolve(),modal))).catch(_notification.default.exception)};_exports.init=(root,view)=>{(0,_prefetch.prefetchStrings)("calendar",["moreevents"]),foldDayEvents(),(root=>{(root=(0,_jquery.default)(root)).on("click",CalendarSelectors.links.eventLink,(e=>{const target=e.target;let eventLink=null,eventId=null;const pendingPromise=new _pending.default("core_calendar/view_manager:eventLink:click");eventLink=target.matches(CalendarSelectors.actions.viewEvent)?target:target.closest(CalendarSelectors.actions.viewEvent),eventId=eventLink?eventLink.dataset.eventId:target.querySelector(CalendarSelectors.actions.viewEvent).dataset.eventId,eventId?(e.preventDefault(),e.stopPropagation(),renderEventSummaryModal(eventId).then(pendingPromise.resolve).catch()):pendingPromise.resolve()})),root.on("click",CalendarSelectors.links.navLink,(e=>{const wrapper=root.find(CalendarSelectors.wrapper),view=wrapper.data("view"),courseId=wrapper.data("courseid"),categoryId=wrapper.data("categoryid"),link=e.currentTarget;"month"===view||"monthblock"===view?(changeMonth(root,link.href,link.dataset.year,link.dataset.month,courseId,categoryId,link.dataset.day),e.preventDefault()):"day"===view&&(changeDay(root,link.href,link.dataset.year,link.dataset.month,link.dataset.day,courseId,categoryId),e.preventDefault())}));const viewSelector=root.find(CalendarSelectors.viewSelector);_custom_interaction_events.default.define(viewSelector,[_custom_interaction_events.default.events.activate]),viewSelector.on(_custom_interaction_events.default.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;"month"==view?refreshMonthContent(root,year,month,courseId,categoryId,root,"core_calendar/calendar_month",day).then((()=>{updateUrl("?view=month&course="+courseId)})).fail(_notification.default.exception):"day"==view?refreshDayContent(root,year,month,day,courseId,categoryId,root,"core_calendar/calendar_day").then((()=>{updateUrl("?view=day&course="+courseId)})).fail(_notification.default.exception):"upcoming"==view&&reloadCurrentUpcoming(root,courseId,categoryId,root,"core_calendar/calendar_upcoming").then((()=>{updateUrl("?view=upcoming&course="+courseId)})).fail(_notification.default.exception)}))})(root);const calendarTable=root.find(CalendarSelectors.elements.monthDetailed);if(calendarTable.length){"month-detailed-".concat(calendarTable.id,"-filterChanged");registerEventListenersForMonthDetailed(calendarTable)}};_exports.handleCourseChange=async(courseId,courseName)=>{document.querySelector(CalendarSelectors.viewSelector+" ul").querySelectorAll("li a").forEach((element=>{element.setAttribute("data-courseid",courseId)}));const calendar=await(0,_str.getString)("calendar","calendar"),pageHeaderHeadingsElement=document.querySelector(CalendarSelectors.pageHeaderHeadings),courseUrl=_url.default.relativeUrl("/course/view.php",{id:courseId});courseId!==_config.default.siteId?pageHeaderHeadingsElement.innerHTML=calendar+': '+courseName+"":pageHeaderHeadingsElement.innerHTML=calendar}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.updateUrl=_exports.reloadCurrentUpcoming=_exports.reloadCurrentMonth=_exports.reloadCurrentDay=_exports.registerEventListenersForMonthDetailed=_exports.refreshMonthContent=_exports.refreshDayContent=_exports.init=_exports.handleCourseChange=_exports.foldDayEvents=_exports.changeMonth=_exports.changeDay=void 0,_jquery=_interopRequireDefault(_jquery),_templates=_interopRequireDefault(_templates),_notification=_interopRequireDefault(_notification),CalendarRepository=_interopRequireWildcard(CalendarRepository),_events=_interopRequireDefault(_events),CalendarSelectors=_interopRequireWildcard(CalendarSelectors),_modal_events=_interopRequireDefault(_modal_events),_summary_modal=_interopRequireDefault(_summary_modal),_custom_interaction_events=_interopRequireDefault(_custom_interaction_events),_pending=_interopRequireDefault(_pending),_url=_interopRequireDefault(_url),_config=_interopRequireDefault(_config);const foldDayEvents=()=>{const days=(0,_jquery.default)(CalendarSelectors.elements.monthDetailed).find(CalendarSelectors.day);0!==days.length&&days.each((function(){const dayContainer=(0,_jquery.default)(this),eventsSelector="".concat(CalendarSelectors.elements.dateContent," ul li[data-event-eventtype]"),filteredEventsSelector="".concat(CalendarSelectors.elements.dateContent,' ul li[data-event-filtered="true"]'),moreEventsSelector="".concat(CalendarSelectors.elements.dateContent,' [data-action="view-more-events"]'),events=dayContainer.find(eventsSelector);if(0===events.length)return;const numberOfFiltered=dayContainer.find(filteredEventsSelector).length,numberOfEvents=events.length-numberOfFiltered;let count=1;events.each((function(){const event=(0,_jquery.default)(this);"true"!==event.attr("data-event-filtered")?count>5-(5===numberOfEvents?0:1)?(event.attr("data-event-folded","true"),event.hide()):(event.attr("data-event-folded","false"),event.show(),count++):event.attr("data-event-folded","false")}));const moreEventsLink=dayContainer.find(moreEventsSelector);if(numberOfEvents>5){const numberOfHiddenEvents=numberOfEvents-5+1;moreEventsLink.show(),(0,_str.getString)("moreevents","calendar",numberOfHiddenEvents).then((str=>{const link=moreEventsLink.find("strong a");return moreEventsLink.attr("data-event-folded","false"),link.text(str),str})).catch(_notification.default.exception)}else moreEventsLink.hide()}))};_exports.foldDayEvents=foldDayEvents;const registerEventListenersForMonthDetailed=pendingId=>{const events="".concat(_events.default.viewUpdated);(0,_jquery.default)("body").on(events,(function(e){foldDayEvents()})),foldDayEvents(),(0,_jquery.default)("body").on(_events.default.filterChanged,(function(e,data){const root=(0,_jquery.default)(CalendarSelectors.elements.monthDetailed),pending=new _pending.default(pendingId),target=root.find(CalendarSelectors.eventType[data.type]),transitionPromise=_jquery.default.Deferred();data.hidden?transitionPromise.then((function(){return target.attr("data-event-filtered","true"),target.hide().promise()})).fail():transitionPromise.then((function(){return target.attr("data-event-filtered","false"),target.show().promise()})).fail(),transitionPromise.then((function(){foldDayEvents()})).always(pending.resolve).fail(),transitionPromise.resolve()}))};_exports.registerEventListenersForMonthDetailed=registerEventListenersForMonthDetailed;const refreshMonthContent=function(root,year,month,courseId,categoryId){let target=arguments.length>5&&void 0!==arguments[5]?arguments[5]:null,template=arguments.length>6&&void 0!==arguments[6]?arguments[6]:"",day=arguments.length>7&&void 0!==arguments[7]?arguments[7]: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"),mini=root.data("mini"),viewMode=target.data("view");return CalendarRepository.getCalendarMonthData(year,month,courseId,categoryId,includenavigation,mini,day,viewMode).then((context=>_templates.default.render(template,context))).then(((html,js)=>_templates.default.replaceNode(target,html,js))).then((()=>{document.querySelector("body").dispatchEvent(new CustomEvent(_events.default.viewUpdated))})).always((()=>(M.util.js_complete([root.get("id"),year,month,courseId].join("-")),stopLoading(root)))).fail(_notification.default.exception)};_exports.refreshMonthContent=refreshMonthContent;const changeMonth=function(root,url,year,month,courseId,categoryId){let day=arguments.length>6&&void 0!==arguments[6]?arguments[6]:1,isCalendarBlock=arguments.length>7&&void 0!==arguments[7]&&arguments[7];return refreshMonthContent(root,year,month,courseId,categoryId,null,"",day).then((function(){url.length&&"#"!==url&&!isCalendarBlock&&updateUrl(url);for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++)args[_key]=arguments[_key];return args})).then((function(){(0,_jquery.default)("body").trigger(_events.default.monthChanged,[year,month,courseId,categoryId,day,isCalendarBlock]);for(var _len2=arguments.length,args=new Array(_len2),_key2=0;_key2<_len2;_key2++)args[_key2]=arguments[_key2];return args}))};_exports.changeMonth=changeMonth;_exports.reloadCurrentMonth=function(root){let courseId=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,categoryId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;const year=root.find(CalendarSelectors.wrapper).data("year"),month=root.find(CalendarSelectors.wrapper).data("month"),day=root.find(CalendarSelectors.wrapper).data("day");return courseId=courseId||root.find(CalendarSelectors.wrapper).data("courseid"),categoryId=categoryId||root.find(CalendarSelectors.wrapper).data("categoryid"),refreshMonthContent(root,year,month,courseId,categoryId,null,"",day).then((function(){(0,_jquery.default)("body").trigger(_events.default.courseChanged,[year,month,courseId,categoryId]);for(var _len3=arguments.length,args=new Array(_len3),_key3=0;_key3<_len3;_key3++)args[_key3]=arguments[_key3];return args}))};const refreshDayContent=function(root,year,month,day,courseId,categoryId){let target=arguments.length>6&&void 0!==arguments[6]?arguments[6]:null,template=arguments.length>7&&void 0!==arguments[7]?arguments[7]:"",isCalendarBlock=arguments.length>8&&void 0!==arguments[8]&&arguments[8];startLoading(root),target&&0!=target.length||(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=!0,context.showviewselector=!0,context.iscalendarblock=isCalendarBlock,_templates.default.render(template,context)))).then(((html,js)=>_templates.default.replaceNode(target,html,js))).then((()=>{document.querySelector("body").dispatchEvent(new CustomEvent(_events.default.viewUpdated))})).always((()=>(M.util.js_complete([root.get("id"),year,month,day,courseId,categoryId].join("-")),stopLoading(root)))).fail(_notification.default.exception)};_exports.refreshDayContent=refreshDayContent;_exports.reloadCurrentDay=function(root){let courseId=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,categoryId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;const wrapper=root.find(CalendarSelectors.wrapper),year=wrapper.data("year"),month=wrapper.data("month"),day=wrapper.data("day");return courseId=courseId||root.find(CalendarSelectors.wrapper).data("courseid"),categoryId=categoryId||root.find(CalendarSelectors.wrapper).data("categoryid"),refreshDayContent(root,year,month,day,courseId,categoryId)};const changeDay=function(root,url,year,month,day,courseId,categoryId){let isCalendarBlock=arguments.length>7&&void 0!==arguments[7]&&arguments[7];return refreshDayContent(root,year,month,day,courseId,categoryId,null,"",isCalendarBlock).then((function(){url.length&&"#"!==url&&!isCalendarBlock&&updateUrl(url);for(var _len4=arguments.length,args=new Array(_len4),_key4=0;_key4<_len4;_key4++)args[_key4]=arguments[_key4];return args})).then((function(){(0,_jquery.default)("body").trigger(_events.default.dayChanged,[year,month,courseId,categoryId,isCalendarBlock]);for(var _len5=arguments.length,args=new Array(_len5),_key5=0;_key5<_len5;_key5++)args[_key5]=arguments[_key5];return args}))};_exports.changeDay=changeDay;const updateUrl=url=>{document.getElementById(CalendarSelectors.fullCalendarView)&&window.history.pushState({},"",url)};_exports.updateUrl=updateUrl;const startLoading=root=>{root.find(CalendarSelectors.containers.loadingIcon).removeClass("hidden")},stopLoading=root=>{root.find(CalendarSelectors.containers.loadingIcon).addClass("hidden")},reloadCurrentUpcoming=function(root){let courseId=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,categoryId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,target=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,template=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"";return 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"),CalendarRepository.getCalendarUpcomingData(courseId,categoryId).then((context=>(context.viewingupcoming=!0,context.showviewselector=!0,_templates.default.render(template,context)))).then(((html,js)=>_templates.default.replaceNode(target,html,js))).then((()=>{document.querySelector("body").dispatchEvent(new CustomEvent(_events.default.viewUpdated))})).always((function(){return stopLoading(root)})).fail(_notification.default.exception)};_exports.reloadCurrentUpcoming=reloadCurrentUpcoming;const renderEventSummaryModal=eventId=>{const pendingPromise=new _pending.default("core_calendar/view_manager:renderEventSummaryModal");return CalendarRepository.getEventById(eventId).then((getEventResponse=>{if(!getEventResponse.event)throw new Error("Error encountered while trying to fetch calendar event with ID: "+eventId);return getEventResponse.event})).then((eventData=>{const modalParams={title:eventData.name,body:_templates.default.render("core_calendar/event_summary_body",eventData),templateContext:{canedit:eventData.canedit,candelete:eventData.candelete,headerclasses:(eventType=eventData.normalisedeventtype,"calendar_event_"+eventType),isactionevent:eventData.isactionevent,url:eventData.url,action:eventData.action}};var eventType;return _summary_modal.default.create(modalParams)})).then((modal=>(modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show(),modal))).then((modal=>(pendingPromise.resolve(),modal))).catch(_notification.default.exception)};_exports.init=(root,view,isCalendarBlock)=>{(0,_prefetch.prefetchStrings)("calendar",["moreevents"]),foldDayEvents(),((root,isCalendarBlock)=>{(root=(0,_jquery.default)(root)).on("click",CalendarSelectors.links.eventLink,(e=>{const target=e.target;let eventLink=null,eventId=null;const pendingPromise=new _pending.default("core_calendar/view_manager:eventLink:click");eventLink=target.matches(CalendarSelectors.actions.viewEvent)?target:target.closest(CalendarSelectors.actions.viewEvent),eventId=eventLink?eventLink.dataset.eventId:target.querySelector(CalendarSelectors.actions.viewEvent).dataset.eventId,eventId?(e.preventDefault(),e.stopPropagation(),renderEventSummaryModal(eventId).then(pendingPromise.resolve).catch()):pendingPromise.resolve()})),root.on("click",CalendarSelectors.links.navLink,(e=>{const wrapper=root.find(CalendarSelectors.wrapper),view=wrapper.data("view"),courseId=wrapper.data("courseid"),categoryId=wrapper.data("categoryid"),link=e.currentTarget;"month"===view||"monthblock"===view?(changeMonth(root,link.href,link.dataset.year,link.dataset.month,courseId,categoryId,link.dataset.day,isCalendarBlock),e.preventDefault()):"day"===view&&(changeDay(root,link.href,link.dataset.year,link.dataset.month,link.dataset.day,courseId,categoryId,isCalendarBlock),e.preventDefault())}));const viewSelector=root.find(CalendarSelectors.viewSelector);_custom_interaction_events.default.define(viewSelector,[_custom_interaction_events.default.events.activate]),viewSelector.on(_custom_interaction_events.default.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;"month"==view?refreshMonthContent(root,year,month,courseId,categoryId,root,"core_calendar/calendar_month",day).then((()=>{updateUrl("?view=month&course="+courseId)})).fail(_notification.default.exception):"day"==view?refreshDayContent(root,year,month,day,courseId,categoryId,root,"core_calendar/calendar_day").then((()=>{updateUrl("?view=day&course="+courseId)})).fail(_notification.default.exception):"upcoming"==view&&reloadCurrentUpcoming(root,courseId,categoryId,root,"core_calendar/calendar_upcoming").then((()=>{updateUrl("?view=upcoming&course="+courseId)})).fail(_notification.default.exception)}))})(root,isCalendarBlock);const calendarTable=root.find(CalendarSelectors.elements.monthDetailed);if(calendarTable.length){"month-detailed-".concat(calendarTable.id,"-filterChanged");registerEventListenersForMonthDetailed(calendarTable)}};_exports.handleCourseChange=async(courseId,courseName)=>{document.querySelector(CalendarSelectors.viewSelector+" ul").querySelectorAll("li a").forEach((element=>{element.setAttribute("data-courseid",courseId)}));const calendar=await(0,_str.getString)("calendar","calendar"),pageHeaderHeadingsElement=document.querySelector(CalendarSelectors.pageHeaderHeadings),courseUrl=_url.default.relativeUrl("/course/view.php",{id:courseId});courseId!==_config.default.siteId?pageHeaderHeadingsElement.innerHTML=calendar+': '+courseName+"":pageHeaderHeadingsElement.innerHTML=calendar}})); //# sourceMappingURL=view_manager.min.js.map \ No newline at end of file diff --git a/calendar/amd/build/view_manager.min.js.map b/calendar/amd/build/view_manager.min.js.map index 6e84fa0ed87..01bd18866d2 100644 --- a/calendar/amd/build/view_manager.min.js.map +++ b/calendar/amd/build/view_manager.min.js.map @@ -1 +1 @@ -{"version":3,"file":"view_manager.min.js","sources":["../src/view_manager.js"],"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 ModalEvents from 'core/modal_events';\nimport SummaryModal from 'core_calendar/summary_modal';\nimport CustomEvents from 'core/custom_interaction_events';\nimport {getString} from 'core/str';\nimport Pending from 'core/pending';\nimport {prefetchStrings} from 'core/prefetch';\nimport Url from 'core/url';\nimport Config from 'core/config';\n\n/**\n * Limit number of events per day\n *\n */\nconst LIMIT_DAY_EVENTS = 5;\n\n/**\n * Hide day events if more than 5.\n *\n */\nexport const foldDayEvents = () => {\n const root = $(CalendarSelectors.elements.monthDetailed);\n const days = root.find(CalendarSelectors.day);\n if (days.length === 0) {\n return;\n }\n days.each(function() {\n const dayContainer = $(this);\n const eventsSelector = `${CalendarSelectors.elements.dateContent} ul li[data-event-eventtype]`;\n const filteredEventsSelector = `${CalendarSelectors.elements.dateContent} ul li[data-event-filtered=\"true\"]`;\n const moreEventsSelector = `${CalendarSelectors.elements.dateContent} [data-action=\"view-more-events\"]`;\n const events = dayContainer.find(eventsSelector);\n if (events.length === 0) {\n return;\n }\n\n const filteredEvents = dayContainer.find(filteredEventsSelector);\n const numberOfFiltered = filteredEvents.length;\n const numberOfEvents = events.length - numberOfFiltered;\n\n let count = 1;\n events.each(function() {\n const event = $(this);\n const isNotFiltered = event.attr('data-event-filtered') !== 'true';\n const offset = (numberOfEvents === LIMIT_DAY_EVENTS) ? 0 : 1;\n if (isNotFiltered) {\n if (count > LIMIT_DAY_EVENTS - offset) {\n event.attr('data-event-folded', 'true');\n event.hide();\n } else {\n event.attr('data-event-folded', 'false');\n event.show();\n count++;\n }\n } else {\n // It's being filtered out.\n event.attr('data-event-folded', 'false');\n }\n });\n\n const moreEventsLink = dayContainer.find(moreEventsSelector);\n if (numberOfEvents > LIMIT_DAY_EVENTS) {\n const numberOfHiddenEvents = numberOfEvents - LIMIT_DAY_EVENTS + 1;\n moreEventsLink.show();\n getString('moreevents', 'calendar', numberOfHiddenEvents).then(str => {\n const link = moreEventsLink.find('strong a');\n moreEventsLink.attr('data-event-folded', 'false');\n link.text(str);\n return str;\n }).catch(Notification.exception);\n } else {\n moreEventsLink.hide();\n }\n });\n};\n\n/**\n * Register and handle month calendar events.\n *\n * @param {string} pendingId pending id.\n */\nexport const registerEventListenersForMonthDetailed = (pendingId) => {\n const events = `${CalendarEvents.viewUpdated}`;\n $('body').on(events, function(e) {\n foldDayEvents(e);\n });\n foldDayEvents();\n $('body').on(CalendarEvents.filterChanged, function(e, data) {\n const root = $(CalendarSelectors.elements.monthDetailed);\n const pending = new Pending(pendingId);\n const target = root.find(CalendarSelectors.eventType[data.type]);\n const transitionPromise = $.Deferred();\n if (data.hidden) {\n transitionPromise.then(function() {\n target.attr('data-event-filtered', 'true');\n return target.hide().promise();\n }).fail();\n } else {\n transitionPromise.then(function() {\n target.attr('data-event-filtered', 'false');\n return target.show().promise();\n }).fail();\n }\n\n transitionPromise.then(function() {\n foldDayEvents();\n return;\n })\n .always(pending.resolve)\n .fail();\n\n transitionPromise.resolve();\n });\n};\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&course=' + courseId);\n return;\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&course=' + courseId);\n return;\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&course=' + courseId);\n return;\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 then((...args) => {\n $('body').trigger(CalendarEvents.courseChanged, [year, month, courseId, categoryId]);\n return args;\n });\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 if (!target || target.length == 0){\n target = root.find(CalendarSelectors.wrapper);\n }\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 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 SummaryModal.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 prefetchStrings('calendar', ['moreevents']);\n foldDayEvents();\n registerEventListeners(root, view);\n const calendarTable = root.find(CalendarSelectors.elements.monthDetailed);\n if (calendarTable.length) {\n const pendingId = `month-detailed-${calendarTable.id}-filterChanged`;\n registerEventListenersForMonthDetailed(calendarTable, pendingId);\n }\n};\n\n/**\n * Handles the change of course and updates the relevant elements on the page.\n *\n * @param {integer} courseId - The ID of the new course.\n * @param {string} courseName - The name of the new course.\n * @returns {Promise} - A promise that resolves after the updates are applied.\n */\nexport const handleCourseChange = async(courseId, courseName) => {\n // Select the
    element inside the data-region=\"view-selector\".\n const ulElement = document.querySelector(CalendarSelectors.viewSelector + ' ul');\n // Select all
  • elements within the
      .\n const liElements = ulElement.querySelectorAll('li a');\n // Loop through the selected elements and update the courseid.\n liElements.forEach(element => {\n element.setAttribute('data-courseid', courseId);\n });\n\n const calendar = await getString('calendar', 'calendar');\n const pageHeaderHeadingsElement = document.querySelector(CalendarSelectors.pageHeaderHeadings);\n const courseUrl = Url.relativeUrl('/course/view.php', {id: courseId});\n // Apply the page header text.\n if (courseId !== Config.siteId) {\n pageHeaderHeadingsElement.innerHTML = calendar + ': ' + courseName + '';\n } else {\n pageHeaderHeadingsElement.innerHTML = calendar;\n }\n};"],"names":["foldDayEvents","days","CalendarSelectors","elements","monthDetailed","find","day","length","each","dayContainer","this","eventsSelector","dateContent","filteredEventsSelector","moreEventsSelector","events","numberOfFiltered","numberOfEvents","count","event","attr","hide","show","moreEventsLink","numberOfHiddenEvents","then","str","link","text","catch","Notification","exception","registerEventListenersForMonthDetailed","pendingId","CalendarEvents","viewUpdated","on","e","filterChanged","data","root","pending","Pending","target","eventType","type","transitionPromise","$","Deferred","hidden","promise","fail","always","resolve","refreshMonthContent","year","month","courseId","categoryId","template","startLoading","wrapper","M","util","js_pending","get","join","includenavigation","mini","viewMode","CalendarRepository","getCalendarMonthData","context","Templates","render","html","js","replaceNode","document","querySelector","dispatchEvent","CustomEvent","js_complete","stopLoading","changeMonth","url","updateUrl","args","trigger","monthChanged","courseChanged","refreshDayContent","getCalendarDayData","viewingday","showviewselector","changeDay","dayChanged","getElementById","fullCalendarView","window","history","pushState","containers","loadingIcon","removeClass","addClass","reloadCurrentUpcoming","getCalendarUpcomingData","viewingupcoming","renderEventSummaryModal","eventId","pendingPromise","getEventById","getEventResponse","Error","eventData","modalParams","title","name","body","templateContext","canedit","candelete","headerclasses","normalisedeventtype","isactionevent","action","SummaryModal","create","modal","getRoot","ModalEvents","destroy","view","links","eventLink","matches","actions","viewEvent","closest","dataset","preventDefault","stopPropagation","navLink","currentTarget","href","viewSelector","define","CustomEvents","activate","option","classList","contains","courseid","categoryid","registerEventListeners","calendarTable","id","async","courseName","querySelectorAll","forEach","element","setAttribute","calendar","pageHeaderHeadingsElement","pageHeaderHeadings","courseUrl","Url","relativeUrl","Config","siteId","innerHTML"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"view_manager.min.js","sources":["../src/view_manager.js"],"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 ModalEvents from 'core/modal_events';\nimport SummaryModal from 'core_calendar/summary_modal';\nimport CustomEvents from 'core/custom_interaction_events';\nimport {getString} from 'core/str';\nimport Pending from 'core/pending';\nimport {prefetchStrings} from 'core/prefetch';\nimport Url from 'core/url';\nimport Config from 'core/config';\n\n/**\n * Limit number of events per day\n *\n */\nconst LIMIT_DAY_EVENTS = 5;\n\n/**\n * Hide day events if more than 5.\n *\n */\nexport const foldDayEvents = () => {\n const root = $(CalendarSelectors.elements.monthDetailed);\n const days = root.find(CalendarSelectors.day);\n if (days.length === 0) {\n return;\n }\n days.each(function() {\n const dayContainer = $(this);\n const eventsSelector = `${CalendarSelectors.elements.dateContent} ul li[data-event-eventtype]`;\n const filteredEventsSelector = `${CalendarSelectors.elements.dateContent} ul li[data-event-filtered=\"true\"]`;\n const moreEventsSelector = `${CalendarSelectors.elements.dateContent} [data-action=\"view-more-events\"]`;\n const events = dayContainer.find(eventsSelector);\n if (events.length === 0) {\n return;\n }\n\n const filteredEvents = dayContainer.find(filteredEventsSelector);\n const numberOfFiltered = filteredEvents.length;\n const numberOfEvents = events.length - numberOfFiltered;\n\n let count = 1;\n events.each(function() {\n const event = $(this);\n const isNotFiltered = event.attr('data-event-filtered') !== 'true';\n const offset = (numberOfEvents === LIMIT_DAY_EVENTS) ? 0 : 1;\n if (isNotFiltered) {\n if (count > LIMIT_DAY_EVENTS - offset) {\n event.attr('data-event-folded', 'true');\n event.hide();\n } else {\n event.attr('data-event-folded', 'false');\n event.show();\n count++;\n }\n } else {\n // It's being filtered out.\n event.attr('data-event-folded', 'false');\n }\n });\n\n const moreEventsLink = dayContainer.find(moreEventsSelector);\n if (numberOfEvents > LIMIT_DAY_EVENTS) {\n const numberOfHiddenEvents = numberOfEvents - LIMIT_DAY_EVENTS + 1;\n moreEventsLink.show();\n getString('moreevents', 'calendar', numberOfHiddenEvents).then(str => {\n const link = moreEventsLink.find('strong a');\n moreEventsLink.attr('data-event-folded', 'false');\n link.text(str);\n return str;\n }).catch(Notification.exception);\n } else {\n moreEventsLink.hide();\n }\n });\n};\n\n/**\n * Register and handle month calendar events.\n *\n * @param {string} pendingId pending id.\n */\nexport const registerEventListenersForMonthDetailed = (pendingId) => {\n const events = `${CalendarEvents.viewUpdated}`;\n $('body').on(events, function(e) {\n foldDayEvents(e);\n });\n foldDayEvents();\n $('body').on(CalendarEvents.filterChanged, function(e, data) {\n const root = $(CalendarSelectors.elements.monthDetailed);\n const pending = new Pending(pendingId);\n const target = root.find(CalendarSelectors.eventType[data.type]);\n const transitionPromise = $.Deferred();\n if (data.hidden) {\n transitionPromise.then(function() {\n target.attr('data-event-filtered', 'true');\n return target.hide().promise();\n }).fail();\n } else {\n transitionPromise.then(function() {\n target.attr('data-event-filtered', 'false');\n return target.show().promise();\n }).fail();\n }\n\n transitionPromise.then(function() {\n foldDayEvents();\n return;\n })\n .always(pending.resolve)\n .fail();\n\n transitionPromise.resolve();\n });\n};\n\n/**\n * Register event listeners for the module.\n *\n * @param {object} root The root element.\n * @param {boolean} isCalendarBlock - A flag indicating whether this is a calendar block.\n */\nconst registerEventListeners = (root, isCalendarBlock) => {\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,\n courseId, categoryId, link.dataset.day, isCalendarBlock);\n e.preventDefault();\n } else if (view === 'day') {\n changeDay(root, link.href, link.dataset.year, link.dataset.month, link.dataset.day,\n courseId, categoryId, isCalendarBlock);\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&course=' + courseId);\n return;\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&course=' + courseId);\n return;\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&course=' + courseId);\n return;\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 * @param {boolean} [isCalendarBlock=false] - A flag indicating whether this is a calendar block.\n * @return {promise}\n */\nexport const changeMonth = (root, url, year, month, courseId, categoryId, day = 1, isCalendarBlock = false) => {\n return refreshMonthContent(root, year, month, courseId, categoryId, null, '', day)\n .then((...args) => {\n if (url.length && url !== '#' && !isCalendarBlock) {\n updateUrl(url);\n }\n return args;\n })\n .then((...args) => {\n $('body').trigger(CalendarEvents.monthChanged, [year, month, courseId, categoryId, day, isCalendarBlock]);\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 then((...args) => {\n $('body').trigger(CalendarEvents.courseChanged, [year, month, courseId, categoryId]);\n return args;\n });\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 * @param {boolean} isCalendarBlock - A flag indicating whether this is a calendar block.\n *\n * @return {promise}\n */\nexport const refreshDayContent = (root, year, month, day, courseId, categoryId,\n target = null, template = '', isCalendarBlock = false) => {\n startLoading(root);\n\n if (!target || target.length == 0){\n target = root.find(CalendarSelectors.wrapper);\n }\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 context.iscalendarblock = isCalendarBlock;\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 * @param {boolean} [isCalendarBlock=false] - A flag indicating whether this is a calendar block.\n * @return {promise}\n */\nexport const changeDay = (root, url, year, month, day, courseId, categoryId, isCalendarBlock = false) => {\n return refreshDayContent(root, year, month, day, courseId, categoryId, null, '', isCalendarBlock)\n .then((...args) => {\n if (url.length && url !== '#' && !isCalendarBlock) {\n updateUrl(url);\n }\n return args;\n })\n .then((...args) => {\n $('body').trigger(CalendarEvents.dayChanged, [year, month, courseId, categoryId, isCalendarBlock]);\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 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 SummaryModal.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\n/**\n * Initializes the calendar component by prefetching strings, folding day events,\n * and registering event listeners.\n *\n * @param {HTMLElement} root - The root element where the calendar view manager and event listeners will be attached.\n * @param {string} view - A flag indicating whether this is a calendar block.\n * @param {boolean} isCalendarBlock - A flag indicating whether this is a calendar block.\n */\nexport const init = (root, view, isCalendarBlock) => {\n prefetchStrings('calendar', ['moreevents']);\n foldDayEvents();\n registerEventListeners(root, isCalendarBlock);\n const calendarTable = root.find(CalendarSelectors.elements.monthDetailed);\n if (calendarTable.length) {\n const pendingId = `month-detailed-${calendarTable.id}-filterChanged`;\n registerEventListenersForMonthDetailed(calendarTable, pendingId);\n }\n};\n\n/**\n * Handles the change of course and updates the relevant elements on the page.\n *\n * @param {integer} courseId - The ID of the new course.\n * @param {string} courseName - The name of the new course.\n * @returns {Promise} - A promise that resolves after the updates are applied.\n */\nexport const handleCourseChange = async(courseId, courseName) => {\n // Select the
        element inside the data-region=\"view-selector\".\n const ulElement = document.querySelector(CalendarSelectors.viewSelector + ' ul');\n // Select all
      • elements within the
          .\n const liElements = ulElement.querySelectorAll('li a');\n // Loop through the selected elements and update the courseid.\n liElements.forEach(element => {\n element.setAttribute('data-courseid', courseId);\n });\n\n const calendar = await getString('calendar', 'calendar');\n const pageHeaderHeadingsElement = document.querySelector(CalendarSelectors.pageHeaderHeadings);\n const courseUrl = Url.relativeUrl('/course/view.php', {id: courseId});\n // Apply the page header text.\n if (courseId !== Config.siteId) {\n pageHeaderHeadingsElement.innerHTML = calendar + ': ' + courseName + '';\n } else {\n pageHeaderHeadingsElement.innerHTML = calendar;\n }\n};"],"names":["foldDayEvents","days","CalendarSelectors","elements","monthDetailed","find","day","length","each","dayContainer","this","eventsSelector","dateContent","filteredEventsSelector","moreEventsSelector","events","numberOfFiltered","numberOfEvents","count","event","attr","hide","show","moreEventsLink","numberOfHiddenEvents","then","str","link","text","catch","Notification","exception","registerEventListenersForMonthDetailed","pendingId","CalendarEvents","viewUpdated","on","e","filterChanged","data","root","pending","Pending","target","eventType","type","transitionPromise","$","Deferred","hidden","promise","fail","always","resolve","refreshMonthContent","year","month","courseId","categoryId","template","startLoading","wrapper","M","util","js_pending","get","join","includenavigation","mini","viewMode","CalendarRepository","getCalendarMonthData","context","Templates","render","html","js","replaceNode","document","querySelector","dispatchEvent","CustomEvent","js_complete","stopLoading","changeMonth","url","isCalendarBlock","updateUrl","args","trigger","monthChanged","courseChanged","refreshDayContent","getCalendarDayData","viewingday","showviewselector","iscalendarblock","changeDay","dayChanged","getElementById","fullCalendarView","window","history","pushState","containers","loadingIcon","removeClass","addClass","reloadCurrentUpcoming","getCalendarUpcomingData","viewingupcoming","renderEventSummaryModal","eventId","pendingPromise","getEventById","getEventResponse","Error","eventData","modalParams","title","name","body","templateContext","canedit","candelete","headerclasses","normalisedeventtype","isactionevent","action","SummaryModal","create","modal","getRoot","ModalEvents","destroy","view","links","eventLink","matches","actions","viewEvent","closest","dataset","preventDefault","stopPropagation","navLink","currentTarget","href","viewSelector","define","CustomEvents","activate","option","classList","contains","courseid","categoryid","registerEventListeners","calendarTable","id","async","courseName","querySelectorAll","forEach","element","setAttribute","calendar","pageHeaderHeadingsElement","pageHeaderHeadings","courseUrl","Url","relativeUrl","Config","siteId","innerHTML"],"mappings":"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"} \ No newline at end of file diff --git a/calendar/amd/src/calendar.js b/calendar/amd/src/calendar.js index ee978d65f8a..b725c66381f 100644 --- a/calendar/amd/src/calendar.js +++ b/calendar/amd/src/calendar.js @@ -33,7 +33,6 @@ define([ 'core_calendar/view_manager', 'core_calendar/crud', 'core_calendar/selectors', - 'core/config', 'core/url', 'core/str', ], @@ -46,7 +45,6 @@ function( CalendarViewManager, CalendarCrud, CalendarSelectors, - Config, Url, Str, ) { @@ -171,8 +169,9 @@ function( * Register event listeners for the module. * * @param {object} root The calendar root element + * @param {boolean} isCalendarBlock - A flag indicating whether this is a calendar block. */ - var registerEventListeners = function(root) { + var registerEventListeners = function(root, isCalendarBlock) { const viewingFullCalendar = document.getElementById(CalendarSelectors.fullCalendarView); // Listen the click on the day link to render the day view. root.on('click', SELECTORS.VIEW_DAY_LINK, function(e) { @@ -193,9 +192,13 @@ function( .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) .join('&'); CalendarViewManager.refreshDayContent(root, year, month, day, courseId, categoryId, root, - 'core_calendar/calendar_day').then(function() { + 'core_calendar/calendar_day', isCalendarBlock).then(function() { e.preventDefault(); - return CalendarViewManager.updateUrl(urlParamString); + // Update the URL if it's not calendar block. + if (!isCalendarBlock) { + CalendarViewManager.updateUrl('?' + urlParamString); + } + return; }).catch(Notification.exception); } else { window.location.assign(Url.relativeUrl('calendar/view.php', urlParams)); @@ -266,10 +269,16 @@ function( }; return { - init: function(root) { + /** + * Initializes the calendar view manager and registers event listeners. + * + * @param {HTMLElement} root - The root element where the calendar view manager and event listeners will be attached. + * @param {boolean} [isCalendarBlock=false] - A flag indicating whether this is a calendar block. + */ + init: function(root, isCalendarBlock = false) { root = $(root); - CalendarViewManager.init(root); - registerEventListeners(root); + CalendarViewManager.init(root, 'month', isCalendarBlock); + registerEventListeners(root, isCalendarBlock); } }; }); diff --git a/calendar/amd/src/calendar_view.js b/calendar/amd/src/calendar_view.js index d03678e39cc..f631c950a56 100644 --- a/calendar/amd/src/calendar_view.js +++ b/calendar/amd/src/calendar_view.js @@ -86,11 +86,11 @@ function( }; return { - init: function(root, type) { + init: function(root, type, isCalendarBlock = false) { root = $(root); - CalendarViewManager.init(root, type); - registerEventListeners(root, type); + CalendarViewManager.init(root, type, isCalendarBlock); + registerEventListeners(root, type, isCalendarBlock); } }; }); diff --git a/calendar/amd/src/popover.js b/calendar/amd/src/popover.js index e4434dfb6ef..5a8cba46573 100644 --- a/calendar/amd/src/popover.js +++ b/calendar/amd/src/popover.js @@ -54,7 +54,8 @@ const showPopover = target => { content.html(temptContent.html()); } return content.html(); - } + }, + 'animation': false, }); isPopoverConfigured.set(dateContainer, true); @@ -64,6 +65,8 @@ const showPopover = target => { jQuery(target).popover('show'); target.addEventListener('mouseleave', hidePopover); target.addEventListener('focusout', hidePopover); + // Set up the hide function to the click event type. + target.addEventListener('click', hidePopover); } }; @@ -76,10 +79,23 @@ const hidePopover = e => { if (isPopoverConfigured.has(dateContainer)) { const isTargetActive = target.contains(document.activeElement); const isTargetHover = target.matches(':hover'); + + // Checks if a target element is clicked or pressed. + const isTargetClicked = document.activeElement.contains(target); + + let removeListener = true; if (!isTargetActive && !isTargetHover) { jQuery(target).popover('hide'); + } else if (isTargetClicked) { + jQuery(document.activeElement).popover('hide'); + } else { + removeListener = false; + } + + if (removeListener) { target.removeEventListener('mouseleave', hidePopover); target.removeEventListener('focusout', hidePopover); + target.removeEventListener('click', hidePopover); } } }; diff --git a/calendar/amd/src/view_manager.js b/calendar/amd/src/view_manager.js index 8289b5cb29c..91792a903b4 100644 --- a/calendar/amd/src/view_manager.js +++ b/calendar/amd/src/view_manager.js @@ -145,8 +145,9 @@ export const registerEventListenersForMonthDetailed = (pendingId) => { * Register event listeners for the module. * * @param {object} root The root element. + * @param {boolean} isCalendarBlock - A flag indicating whether this is a calendar block. */ -const registerEventListeners = (root) => { +const registerEventListeners = (root, isCalendarBlock) => { root = $(root); // Bind click events to event links. @@ -192,10 +193,12 @@ const registerEventListeners = (root) => { const link = e.currentTarget; if (view === 'month' || view === 'monthblock') { - changeMonth(root, link.href, link.dataset.year, link.dataset.month, courseId, categoryId, link.dataset.day); + changeMonth(root, link.href, link.dataset.year, link.dataset.month, + courseId, categoryId, link.dataset.day, isCalendarBlock); e.preventDefault(); } else if (view === 'day') { - changeDay(root, link.href, link.dataset.year, link.dataset.month, link.dataset.day, courseId, categoryId); + changeDay(root, link.href, link.dataset.year, link.dataset.month, link.dataset.day, + courseId, categoryId, isCalendarBlock); e.preventDefault(); } }); @@ -292,18 +295,19 @@ export const refreshMonthContent = (root, year, month, courseId, categoryId, tar * @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) + * @param {boolean} [isCalendarBlock=false] - A flag indicating whether this is a calendar block. * @return {promise} */ -export const changeMonth = (root, url, year, month, courseId, categoryId, day = 1) => { +export const changeMonth = (root, url, year, month, courseId, categoryId, day = 1, isCalendarBlock = false) => { return refreshMonthContent(root, year, month, courseId, categoryId, null, '', day) .then((...args) => { - if (url.length && url !== '#') { + if (url.length && url !== '#' && !isCalendarBlock) { updateUrl(url); } return args; }) .then((...args) => { - $('body').trigger(CalendarEvents.monthChanged, [year, month, courseId, categoryId]); + $('body').trigger(CalendarEvents.monthChanged, [year, month, courseId, categoryId, day, isCalendarBlock]); return args; }); }; @@ -343,10 +347,12 @@ export const reloadCurrentMonth = (root, courseId = 0, categoryId = 0) => { * @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 {boolean} isCalendarBlock - A flag indicating whether this is a calendar block. * * @return {promise} */ -export const refreshDayContent = (root, year, month, day, courseId, categoryId, target = null, template = '') => { +export const refreshDayContent = (root, year, month, day, courseId, categoryId, + target = null, template = '', isCalendarBlock = false) => { startLoading(root); if (!target || target.length == 0){ @@ -359,6 +365,7 @@ export const refreshDayContent = (root, year, month, day, courseId, categoryId, .then((context) => { context.viewingday = true; context.showviewselector = true; + context.iscalendarblock = isCalendarBlock; return Templates.render(template, context); }) .then((html, js) => { @@ -405,18 +412,19 @@ export const reloadCurrentDay = (root, courseId = 0, categoryId = 0) => { * @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 {boolean} [isCalendarBlock=false] - A flag indicating whether this is a calendar block. * @return {promise} */ -export const changeDay = (root, url, year, month, day, courseId, categoryId) => { - return refreshDayContent(root, year, month, day, courseId, categoryId) +export const changeDay = (root, url, year, month, day, courseId, categoryId, isCalendarBlock = false) => { + return refreshDayContent(root, year, month, day, courseId, categoryId, null, '', isCalendarBlock) .then((...args) => { - if (url.length && url !== '#') { + if (url.length && url !== '#' && !isCalendarBlock) { updateUrl(url); } return args; }) .then((...args) => { - $('body').trigger(CalendarEvents.dayChanged, [year, month, courseId, categoryId]); + $('body').trigger(CalendarEvents.dayChanged, [year, month, courseId, categoryId, isCalendarBlock]); return args; }); }; @@ -562,10 +570,18 @@ const renderEventSummaryModal = (eventId) => { .catch(Notification.exception); }; -export const init = (root, view) => { +/** + * Initializes the calendar component by prefetching strings, folding day events, + * and registering event listeners. + * + * @param {HTMLElement} root - The root element where the calendar view manager and event listeners will be attached. + * @param {string} view - A flag indicating whether this is a calendar block. + * @param {boolean} isCalendarBlock - A flag indicating whether this is a calendar block. + */ +export const init = (root, view, isCalendarBlock) => { prefetchStrings('calendar', ['moreevents']); foldDayEvents(); - registerEventListeners(root, view); + registerEventListeners(root, isCalendarBlock); const calendarTable = root.find(CalendarSelectors.elements.monthDetailed); if (calendarTable.length) { const pendingId = `month-detailed-${calendarTable.id}-filterChanged`; diff --git a/calendar/templates/calendar_day.mustache b/calendar/templates/calendar_day.mustache index e9ffd4375a8..c813b3143cd 100644 --- a/calendar/templates/calendar_day.mustache +++ b/calendar/templates/calendar_day.mustache @@ -29,6 +29,7 @@ Example context (json): { + "iscalendarblock": false } }}
          @@ -37,6 +38,7 @@
          {{#js}} require(['jquery', 'core_calendar/calendar_view'], function($, CalendarView) { - CalendarView.init($("#calendar-day-{{uniqid}}"), 'day'); + const isCalendarBlock = {{#iscalendarblock}}true{{/iscalendarblock}}{{^iscalendarblock}}false{{/iscalendarblock}}; + CalendarView.init($("#calendar-day-{{uniqid}}"), 'day', isCalendarBlock); }); {{/js}} diff --git a/calendar/templates/calendar_month.mustache b/calendar/templates/calendar_month.mustache index 28517c1e758..11f59abdcd6 100644 --- a/calendar/templates/calendar_month.mustache +++ b/calendar/templates/calendar_month.mustache @@ -29,6 +29,7 @@ Example context (json): { + "iscalendarblock": false } }}
          @@ -37,6 +38,7 @@
          {{#js}} require(['jquery', 'core_calendar/calendar', 'core_calendar/popover'], function($, Calendar, calendarPopover) { - Calendar.init($("#calendar-month-{{uniqid}}-{{calendarinstanceid}}")); + const isCalendarBlock = {{#iscalendarblock}}true{{/iscalendarblock}}{{^iscalendarblock}}false{{/iscalendarblock}}; + Calendar.init($("#calendar-month-{{uniqid}}-{{calendarinstanceid}}"), isCalendarBlock); }); {{/js}} diff --git a/calendar/tests/behat/behat_calendar.php b/calendar/tests/behat/behat_calendar.php index acc758bbd16..75c81ea333a 100644 --- a/calendar/tests/behat/behat_calendar.php +++ b/calendar/tests/behat/behat_calendar.php @@ -132,6 +132,26 @@ class behat_calendar extends behat_base { ); } + /** + * Click on a specific day in the mini-calendar. + * + * @Given /^I click on day "(?P\d+)" of this month in the mini-calendar block(?P responsive view|)$/ + * + * @param int $day The day of the current month. + * @param string $responsive If not null, find the responsive version of the link. + */ + public function i_click_on_day_of_this_month_in_mini_calendar_block(int $day, string $responsive = ''): void { + $this->execute( + contextapi: "behat_general::i_click_on_in_the", + params: [ + $day, + empty($responsive) ? 'core_calendar > calendar day' : 'core_calendar > responsive calendar day', + '', + 'core_calendar > mini calendar block', + ], + ); + } + /** * Hover over today in the mini-calendar. * @@ -144,6 +164,20 @@ class behat_calendar extends behat_base { $this->i_hover_over_day_of_this_month_in_mini_calendar_block($todaysday, $responsive); } + /** + * Click on today in the mini-calendar. + * + * @Given /^I click on today in the mini-calendar block( responsive view|)$/ + * + * @param string $responsive If not empty, use the responsive calendar link. + */ + public function i_click_on_today_in_mini_calendar_block(string $responsive = ''): void { + $this->i_click_on_day_of_this_month_in_mini_calendar_block( + day: date('j'), + responsive: $responsive, + ); + } + /** * Navigate to a specific month in the calendar. *