NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Flatten Zimbra Calendar Background Colors and Grey Elapsed Time and Events // @version 1.6 // @author You // @match https://partage.unistra.fr/* // @grant none // @license MIT // ==/UserScript== //Observer that checks if the calendar node exists var calendarObserver = new MutationObserver(function (mutations, observer) { //If the calendar node exists if (document.getElementsByClassName("ZmCalViewMgr").length > 0) { //regex to identify if the correct style is applied afterwards var re = /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\) none repeat scroll 0% 0%/; //Create an events observer that will change all backgrounds when triggered var eventsObserver = new MutationObserver(function (mutations, observer) { changeBackgroundStyle(eventsObserver, re); }); //Events observer is triggered when background attributes of calendar node or any of its children are modified eventsObserver.observe(document.getElementsByClassName("ZmCalViewMgr")[0], { subtree: true, attributes: true, attributesFilter: ['background', 'opacity'], childList: true }); //We disconnect the calendar observer since the events observer is now up and running calendarObserver.disconnect(); } }); //Calendar observer is triggered whenever a change is made in the document calendarObserver.observe(document, { subtree: true, attributes: true }); //Function to change the backgrounds to a flatter, easier to read format function changeBackgroundStyle(eventsObserver, re) { //Temporarily disconnect the events observer otherwise our background manipulations will trigger an infinite loop (not needed for firefox 66+, how come ?) eventsObserver.disconnect(); //Get current date, day, hours and minutes var currentDate = new Date(); var currentTime = currentDate.getTime(); var lengthOfWorkDay = Date.parse("1970/01/01 17:00") - Date.parse("1970/01/01 8:00"); var advancementOfDay = ((Date.parse("1970/01/01 " + currentDate.getHours() + ':' + currentDate.getMinutes()) - Date.parse("1970/01/01 8:00")) / lengthOfWorkDay * 100).toFixed(1); var displayedYear = document.getElementsByClassName('DwtCalendarTitle')[0].textContent.split(' ')[1]; var displayedWeekStart = document.getElementById('zcalNavText').textContent.split('-')[0].replace(/ /g, '').split('/').reverse().join('/'); var displayedWeekStartTime = Date.parse(displayedYear + '/' + document.getElementById('zcalNavText').textContent.split('-')[0].replace(/ /g, '').split('/').reverse().join('/')); var displayedWeekEndTime = Date.parse(displayedYear + '/' + document.getElementById('zcalNavText').textContent.split('-')[1].replace(/ /g, '').split('/').reverse().join('/')); var fullDayLength = 86400000; //Retrieve all day grids and events var events = document.querySelectorAll('*[id$="_tableBody"]'); var dayGrids = Array.from(document.getElementsByClassName('ImgCalendarDayGrid')); //We remove all even index dayGrids since they're useless for (var i = 0; i < dayGrids.length; i++) { dayGrids.splice(i, 1); } var dayGridIndex = 1; //For all day grids dayGrids.forEach(function (dayGrid) { let dayGridDayStart = displayedWeekStartTime + (dayGridIndex - 1) * fullDayLength; let dayGridDayEnd = displayedWeekStartTime + dayGridIndex * fullDayLength; if (dayGridDayEnd < currentTime) { dayGrid.parentNode.style.background = "rgba(227,227,220,1)"; } else if (dayGridDayEnd > currentTime && currentTime > dayGridDayStart) { dayGrid.parentNode.style.background = "linear-gradient(180deg, rgba(227,227,220,1) 0%, rgba(227,227,220,1) " + advancementOfDay + "%, rgba(255,255,255,1) " + (parseInt(advancementOfDay) + 1) + "%,rgba(255,255,255,1) 100%)"; } else { dayGrid.parentNode.style.background = "rgba(255,255,255,1)"; } dayGridIndex++; }); //For all events events.forEach(function (event) { if (event.parentNode.parentNode.parentNode.parentNode.className != "calendar_body" && event.parentNode.parentNode.parentNode.parentNode.className != "calendar_allday_appt") { return; } //Delete the very small and useless border between the vertical bar and the event box itself event.style.border = 0; //Get event day number (0 is monday, 1 et tuesday etc) let eventDay = Math.floor(parseInt(event.parentNode.parentNode.style.left.split('p')[0]) / 294); //If event has end date node, get its value otherwise based on the height of the event #janky if (event.parentNode.parentNode.parentNode.parentNode.className === "calendar_allday_appt") { var eventEndHour = "23:59"; } else if (event.firstChild.childNodes && event.firstChild.childNodes.length > 2) { eventEndHour = event.firstChild.childNodes[2].textContent; } else { let eventHeight = event.parentNode.style.height; let eventDuration; if (eventHeight === "15.4px") { eventDuration = 15; } else if (eventHeight === "21px") { eventDuration = 30; } else if (eventHeight === "31.5px") { eventDuration = 45; } else if (eventHeight === "42px") { eventDuration = 60; } console.log(event); let eventStartTimeHours = parseInt(event.firstChild.firstChild.textContent.split(':')[0]); let eventStartTimeMinutes = parseInt(event.firstChild.firstChild.textContent.split(':')[1].split(' ')[0]); let eventEndTimeHours = eventStartTimeHours; let eventEndTimeMinutes = (eventStartTimeMinutes + eventDuration) % 60; if (eventEndTimeMinutes <= eventStartTimeMinutes) { eventEndTimeHours += 1; } eventEndHour = eventEndTimeHours + ':' + eventEndTimeMinutes; } var eventEndTime = Date.parse(displayedYear + '/' + displayedWeekStart + ' ' + eventEndHour) + eventDay * fullDayLength; //If event was on an earlier day or ended earlier today make it transparent if (eventEndTime < currentTime) { event.style.opacity = 0.5; } //If the correct style is not applied to the event background if (!re.test(event.style.background)) { //Retrieve the color of the event let eventColor = event.style.background.split("rgb(")[2].split(")")[0]; //Set the background style to a flat version of that color event.style.background = "rgba(" + eventColor + ", 1) repeat scroll 0% 0%"; //Set the background style of the events for which the previous line didn't work because their apperance is linked to the style of a child node (no idea why) event.firstChild.firstChild.style.background = "rgba(" + eventColor + ", 1)"; } //If the correct style is not applied to the state side bar if (event.firstChild.firstChild.firstChild.style.background != "" && !re.test(event.firstChild.firstChild.firstChild.style.background)) { //Set the background style of the small "state" vertical bar let eventStateColor = event.firstChild.firstChild.firstChild.style.background.split("rgb(")[2].split(")")[0]; event.firstChild.firstChild.firstChild.style.background = "rgba(" + eventStateColor + ", 1) repeat scroll 0% 0%"; } }); //Reconnect the events observer eventsObserver.observe(document.getElementsByClassName("ZmCalViewMgr")[0], { subtree: true, attributes: true, attributesFilter: ['background', 'opacity'], childList: true }); }