// Based on https://stackoverflow.com/a/15289883 function computeDateDifferenceInHours (date1, date2) { d1 = new Date(date1.getYear(), date1.getMonth(), date1.getDate(), date1.getHours()); d2 = new Date(date2.getYear(), date2.getMonth(), date2.getDate(), date2.getHours()); const msPerHour = 60 * 60 * 1000; return Math.abs(d2.getTime() - d1.getTime()) / msPerHour; } class Calendar { constructor (calendarParameters = {}) { this.containerNode = calendarParameters.containerNode !== undefined ? calendarParameters.containerNode : $("#cal-container"); this.eventContainerNode = null; this.timeSlotsContainerNode = null; this.eventDetailsContainerNode = null; this.startDate = calendarParameters.startDate !== undefined ? calendarParameters.startDate : new Date(); this.endDate = calendarParameters.endDate !== undefined ? calendarParameters.endDate : new Date(Date.now() + (24 * 60 * 60 * 1000)); this.nbHoursToDisplay = 0; this.firstHourToDisplay = 0; this.endHourToDisplay = 0; this.events = []; this.onlyDisplaySubscribedEvents = calendarParameters.onlyDisplaySubscribedEvents !== undefined ? calendarParameters.onlyDisplaySubscribedEvents : false; this.groupEventsByLocation = calendarParameters.groupEventsByLocation !== undefined ? calendarParameters.groupEventsByLocation : true; this.eventDetailURLFormat = calendarParameters.eventDetailURLFormat !== undefined ? calendarParameters.eventDetailURLFormat : ""; this.subscriptionURLFormat = calendarParameters.subscriptionURLFormat !== undefined ? calendarParameters.subscriptionURLFormat : ""; this.csrfToken = calendarParameters.csrfToken !== undefined ? calendarParameters.csrfToken : ""; // Map from locations to their CSS styles this.locationStyles = new Map(); this.init(); } init () { this.updateHoursToDisplay(); this.createTimeSlotContainer(); this.createEventContainer(); this.createEventDetailsContainer(); this.updateTimeSlotContainerGridStyle(); this.updateEventContainerGridStyle(); this.createTimeSlots(); this.createEvents(); this.createLocationStyles(); this.applyLocationStylesAsCSS(); this.updateEventLocationStyleID(); //this.sortEventNodesByEndTimeAndLocation(); this.sortEventNodesByIntervalGraphColoring(); this.updateCalendarNodeHeight(); this.initEventOverflowTooltips(); } // Date change setStartDate (newStartDate) { this.startDate = newStartDate; this.updateHoursToDisplay(); this.updateEventContainerGridStyle(); this.updateTimeSlots(); this.updateEventVisibilities(); this.updateCalendarNodeHeight(); this.sortEventNodesByIntervalGraphColoring(); this.startShowingEventOverflowTooltips(); } setEndDate (newEndDate) { this.endDate = newEndDate; this.updateHoursToDisplay(); this.updateEventContainerGridStyle(); this.updateTimeSlots(); this.updateEventVisibilities(); this.updateCalendarNodeHeight(); this.sortEventNodesByIntervalGraphColoring(); this.startShowingEventOverflowTooltips(); } updateHoursToDisplay () { this.startHourToDisplay = this.startDate.getHours(); this.endHourToDisplay = this.endDate.getHours(); this.nbHoursToDisplay = Math.floor(computeDateDifferenceInHours(this.startDate, this.endDate)); } // Calendar container updateCalendarNodeHeight () { // Time slot hour row let timeSlotHourRowHeight = $(".cal-time-slot-hour").outerHeight(); // Event grid this.containerNode.css("height", "calc(100% )"); let eventContainerHeight = this.eventContainerNode .css("grid-template-rows") .split("px ") .reduce((heightAccumulator, currentRowHeight) => { return heightAccumulator + parseInt(currentRowHeight); }, 0); this.containerNode.css("height", timeSlotHourRowHeight + eventContainerHeight); } // Time slots createTimeSlotContainer () { this.timeSlotsContainerNode = $("