Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 11
Línea 1... Línea -...
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 <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to handler calendar view changes.\n *\n * @module     core_calendar/view_manager\n * @copyright  2017 Andrew Nicols <andrew@nicols.co.uk>\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<void>} - A promise that resolves after the updates are applied.\n */\nexport const handleCourseChange = async(courseId, courseName) => {\n    // Select the <ul> element inside the data-region=\"view-selector\".\n    const ulElement = document.querySelector(CalendarSelectors.viewSelector + ' ul');\n    // Select all <li><a> elements within the <ul>.\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 + ': <a href=\"' + courseUrl + '\">' + courseName + '</a>';\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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"}
-
 
2
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 <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to handler calendar view changes.\n *\n * @module     core_calendar/view_manager\n * @copyright  2017 Andrew Nicols <andrew@nicols.co.uk>\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<void>} - A promise that resolves after the updates are applied.\n */\nexport const handleCourseChange = async(courseId, courseName) => {\n    // Select the <ul> element inside the data-region=\"view-selector\".\n    const ulElement = document.querySelector(CalendarSelectors.viewSelector + ' ul');\n    // Select all <li><a> elements within the <ul>.\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 + ': <a href=\"' + courseUrl + '\">' + courseName + '</a>';\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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"}
-
 
2
3
3