This repository has been archived on 2022-07-28. You can view files and clone it, but cannot push or open issues or pull requests.
md-cms/js/mdCalendar.js
2018-06-15 11:26:25 +02:00

481 lines
17 KiB
JavaScript

/**
* mdCalendar.js
*/
document.addEventListener("DOMContentLoaded", function() {
/**
* @var {array} translations Array of all translations.
*/
let translations = {
"en" : {
"dow0" : "Sunday",
"dow1" : "Monday",
"dow2" : "Tuesday",
"dow3" : "Wednesday",
"dow4" : "Thursday",
"dow5" : "Friday",
"dow6" : "Saturday",
"mon0" : "January",
"mon1" : "February",
"mon2" : "March",
"mon3" : "April",
"mon4" : "May",
"mon5" : "June",
"mon6" : "July",
"mon7" : "August",
"mon8" : "September",
"mon9" : "October",
"mon10" : "November",
"mon11" : "December",
"Today" : "Today",
"Title" : "Title",
"Start" : "Start",
"End" : "End",
"Location" : "Location"
},
"de" : {
"dow0" : "Sonntag",
"dow1" : "Montag",
"dow2" : "Dienstag",
"dow3" : "Mittwoch",
"dow4" : "Donnerstag",
"dow5" : "Freitag",
"dow6" : "Samstag",
"mon0" : "Januar",
"mon1" : "Februar",
"mon2" : "März",
"mon3" : "April",
"mon4" : "Mai",
"mon5" : "Juni",
"mon6" : "Juli",
"mon7" : "August",
"mon8" : "September",
"mon9" : "Oktober",
"mon10" : "November",
"mon11" : "Dezember",
"Today" : "Jetzt",
"Title" : "Titel",
"Start" : "Beginn",
"End" : "Ende",
"Location" : "Ort"
},
"hu" : {
"dow0": "Vas\u00e1rnap",
"dow1": "H\u00e9tf\u0151",
"dow2": "Kedd",
"dow3": "Szerda",
"dow4": "Cs\u00fct\u00f6rt\u00f6k",
"dow5": "P\u00e9ntek",
"dow6": "Szombat",
"mon0": "Janu\u00e1r",
"mon1": "Febru\u00e1r",
"mon2": "M\u00e1rcius",
"mon3": "\u00c1prilis",
"mon4": "M\u00e1jus",
"mon5": "J\u00fanius",
"mon6": "J\u00falius",
"mon7": "Augusztus",
"mon8": "Szeptember",
"mon9": "Okt\u00f3ber",
"mon10": "November",
"mon11": "December",
"Today": "Ma",
"Title": "C\u00edm",
"Start": "Nyit",
"End": "Bez\u00e1r",
"Location": "Helysz\u00edn"
}
}
/**
* @var {boolean} Toggle debugging.
*/
let debugging = false;
/**
* Function queryPage queries a web page and runs the specified function over the output.
*
* @param {string} url URL to query.
* @param {function} func Callback function to run on the request after loading.
* @param {boolean} debug Enable / disable debug mode.
*
* @return {boolean}
*/
function queryPage(url, func, debug = false) {
let request = new XMLHttpRequest();
request.open('GET', url);
request.setRequestHeader("Cache-Control", "no-cache");
request.responseType = 'htm';
request.send();
request.onload = function() {
func(request, debug);
};
}
/**
* Removes all children of an element.
*
* @param {string} id ID of the element to tear down.
*
* @return {void}
*/
function emptyElement(element) {
while (element.firstChild) {
emptyElement(element.firstChild);
}
element.parentNode.removeChild(element);
if (debugging === true) {
console.log("Removed element:");
console.log(element);
}
}
function tearDownById(id) {
let target = document.getElementById(id);
if (target !== null) emptyElement(target);
}
/**
* Returns a requested translation from an array in the currently used language.
*
* @param {mixed[]} list Translation variable.
* @param {string} specifier Specifies which translation to get.
*
* @return {string}
*/
function getTranslation(list, specifier) {
let preferedLang = document.getElementsByTagName("html")[0].getAttribute("lang");
if (list[preferedLang] !== undefined && list[preferedLang][specifier] !== null) return list[preferedLang][specifier];
return list["en"][specifier];
}
/**
* Function to create calendar.
*/
function createCalendarTable(target, events) {
let startOfWeek = 1; // The week starts on Monday.
let endOfWeek = 0; // The week ends on Sunday.
let calLocale = document.getElementsByTagName("html")[0].getAttribute("lang");
if (calLocale === undefined || calLocale === null) calLocale = "en";
function removeToolTips() {
let toolTips = document.getElementsByClassName("mdCToolTip");
for (let i = 0, max = toolTips.length; i < max; i++) {
emptyElement(toolTips[i]);
}
}
/**
* Gets all days to display per month.
* Adapted version of function described in https://stackoverflow.com/a/13146828.
*
* @param {int} The month number, 0 based
* @param {int} The year, not zero based, required to account for leap years
*
* @return {Date[]} List with date objects for each day of the month
*/
function getDaysInMonth(month, year) {
var date = new Date(year, month, 1);
var days = [];
// If the weekday of the first of the month does not equal 1 (Monday),
// get days until the last monday before the month.
if (date.getDay() !== startOfWeek) {
while (date.getDay() !== startOfWeek) {
date.setDate(date.getDate() - 1);
days.unshift(new Date(date));
}
}
date = new Date(year, month, 1);
// Get days of the month
while (date.getMonth() === month) {
days.push(new Date(date));
date.setDate(date.getDate() + 1);
}
// If the weekday of the first of the month does not equal 1 (Monday),
// get days until the last monday before the month.
while (date.getDay() !== startOfWeek) {
days.push(new Date(date));
date.setDate(date.getDate() + 1);
}
return days;
}
events = (function() {
let colorSchemeLength = 29;
for (var i = 0, max = events.length; i < max; i++) {
let hash = 0;
for (var j = 0, maxj = events[i].name.length; j < maxj; j++) {
hash = events[i].name.charCodeAt(j) + hash;
}
hash = hash % (colorSchemeLength) - 1;
events[i].color = hash;
}
return events;
})();
let d = new Date();
let year;
if (target.getAttribute("data-year") !== null) year = parseInt(target.getAttribute("data-year"));
else year = d.getFullYear();
let month;
if (target.getAttribute("data-month") !== null) month = parseInt(target.getAttribute("data-month") - 1);
else month = d.getMonth();
// Create outer div
let mdCalDiv = document.createElement("div");
mdCalDiv.classList.add("mdCalendar");
/**
* Creater header line of the calendar.
*/
(function() {
let mdCalTitleLine = document.createElement("header");
mdCalTitleLine.classList.add("mdCTitleLine");
let mdCalTitle = document.createElement("h3");
mdCalTitle.textContent = getTranslation(translations, "mon" + month.toString());
if (year != d.getFullYear()) mdCalTitle.textContent = mdCalTitle.textContent + " (" + year + ")";
mdCalTitleLine.appendChild(mdCalTitle);
let mdCalNav = document.createElement("div");
mdCalNav.classList.add("mdCNav");
mdCalTitleLine.appendChild(mdCalNav);
let mdCalNavPrev = document.createElement("a");
mdCalNavPrev.href = target.getAttribute("data-prev");
mdCalNavPrev.rel = "prev";
mdCalNavPrev.classList.add("mdCNavPrev");
mdCalNav.appendChild(mdCalNavPrev);
let mdCalNavNext = document.createElement("a");
mdCalNavNext.href = target.getAttribute("data-next");
mdCalNavNext.rel = "next";
mdCalNavNext.classList.add("mdCNavNext");
mdCalNav.appendChild(mdCalNavNext);
let mdCalNavToday = document.createElement("a");
mdCalNavToday.href = target.getAttribute("data-today");
mdCalNavToday.textContent = getTranslation(translations, "Today");
mdCalNav.appendChild(mdCalNavToday);
mdCalTitleLine.appendChild(mdCalNav);
mdCalDiv.appendChild(mdCalTitleLine);
})();
/**
* Create table.
*/
let table = document.createElement("table");
table.classList.add("mdCTable");
let thead = document.createElement("thead");
let theadTr = document.createElement("tr");
for (let i = 1, max = 7; i < max; i++) {
let th = document.createElement("th");
th.textContent = getTranslation(translations, "dow" + i.toString());
theadTr.appendChild(th);
}
let th = document.createElement("th");
th.textContent = getTranslation(translations, "dow0");
theadTr.appendChild(th);
thead.appendChild(theadTr);
table.appendChild(thead);
let tbody = document.createElement("tbody");
let days = getDaysInMonth(month, year);
let tr;
let daysTDs = [];
function createSingleEventOverlay(e, parentElement, data) {
let toolTip = document.createElement("table");
toolTip.classList.add("mdCToolTip");
let tableData = [];
tableData.push(["Title", data["name"]]);
if (data["start"] !== undefined) tableData.push(["Start", data["start"]]);
if (data["end"] !== undefined) tableData.push(["End", data["end"]]);
if (data["place"] !== undefined) tableData.push(["Location", data["place"]]);
for (let i = 0, max= tableData.length; i < max; i++) {
let nameRow = document.createElement("tr");
let nameTh = document.createElement("th");
nameTh.textContent = getTranslation(translations, tableData[i][0]);
nameRow.appendChild(nameTh);
let nameTd = document.createElement("td");
nameTd.textContent = tableData[i][1];
nameRow.appendChild(nameTd);
toolTip.appendChild(nameRow);
}
parentElement.appendChild(toolTip);
}
for (let i = 0, max= days.length; i < max; i++) {
// Begin a new table row every Monday.
if (days[i].getDay() === startOfWeek) {
tr = document.createElement("tr");
tbody.appendChild(tr);
}
// Create new TD per day and add appropriate classes.
let td = document.createElement("td");
if (days[i].getMonth() !== month) td.classList.add("mdCOtherMonth");
if (days[i].getYear() == d.getYear() && days[i].getMonth() == d.getMonth() && days[i].getDate() == d.getDate()) td.classList.add("mdCToday");
tdTitle = document.createElement("time");
tdTitle.textContent = days[i].getDate();
td.appendChild(tdTitle);
tr.appendChild(td);
// Append dates.
let dayTime = days[i].getTime();
let dayTimeMinusDay = days[i].getTime() + 24 * 3600 * 1000;
let dayTimePlusDay = days[i].getTime() - 0 * 3600 * 1000;
for (let j = 0, maxj = events.length; j < maxj; j++) {
if (Date.parse(events[j].start) > dayTimeMinusDay || Date.parse(events[j].end) < dayTimePlusDay) continue;
let eventSignifier = document.createElement("a");
eventSignifier.classList.add("color" + events[j].color.toString());
if (events[j].link) eventSignifier.href = events[j].link;
let eventSignifierText = document.createElement("span");
eventSignifierText.textContent = events[j].name;
eventSignifier.appendChild(eventSignifierText);
eventSignifier.addEventListener('mouseover', function(e) {
createSingleEventOverlay(e, eventSignifier, events[j]);
});
eventSignifier.addEventListener('mouseout', function(e) {
removeToolTips();
});
td.appendChild(eventSignifier);
}
// Add posibility for overlay.
tdTitle.addEventListener('click', function(e) {
tearDownById("mdCOverlay");
let overlay = document.createElement("div");
overlay.id = "mdCOverlay";
let eventTitleBar = document.createElement("div");
eventTitleBar.classList.add("mdCOverlayTitleBar");
overlay.appendChild(eventTitleBar);
let title = document.createElement("span");
title.classList.add("mdCOverlayTitle");
title.textContent = days[i].toLocaleDateString(calLocale);
eventTitleBar.appendChild(title);
let closer = document.createElement("span");
closer.classList.add("mdCOverlayClose");
closer.addEventListener('click', function(e) {
if (debugging === true) console.log("Clicked close button: Tearing down daily agenda.");
tearDownById("mdCOverlay");
});
eventTitleBar.appendChild(closer);
let ul = document.createElement("ul");
// Append events.
for (let j = 0, maxj = events.length; j < maxj; j++) {
let start = new Date(events[j].start);
let end = new Date(events[j].end);
if (start.getTime() > dayTime || end.getTime() < dayTimePlusDay) continue;
let eventLi = document.createElement("li");
let eventSignifier = document.createElement("a");
eventSignifier.textContent = events[j].name;
if (events[j].link) eventSignifier.href = events[j].link;
eventLi.appendChild(eventSignifier);
let eventP = document.createElement("p");
eventP.textContent = start.toLocaleDateString(calLocale) + " - " + end.toLocaleDateString(calLocale);
if (events[j].place !== undefined) eventP.textContent = eventP.textContent + ", " + events[j].place;
eventLi.appendChild(eventP);
let eventDesc = document.createElement("p");
eventDesc.textContent = events[j].description;
eventLi.appendChild(eventDesc);
ul.appendChild(eventLi);
}
overlay.appendChild(ul);
document.getElementsByTagName("body")[0].appendChild(overlay);
});
if (td.childElementCount > 6) td.classList.add("mdCManyElements");
daysTDs[days[i].getFullYear() + "-" + days[i].getMonth() + "-" + days[i].getDate()] = td;
}
table.appendChild(tbody);
mdCalDiv.appendChild(table);
target.appendChild(mdCalDiv);
// Enable closing overlay by pressing escape.
document.addEventListener('keydown', function(e) {
if (e.keyCode !== 27) return;
if (debugging === true) console.log("Pressed escape: Tearing down daily agenda.");
tearDownById("mdCOverlay");
});
return daysTDs;
}
(function() {
let calendars = document.getElementsByClassName("mdCalendar");
for (let i = 0, max = calendars.length; i < max; i++) {
queryPage(
encodeURI(calendars[i].getAttribute("data-src")),
function (request) {
if (debugging === true) console.log("Loaded\n" + request.response);
let elements = JSON.parse(request.response);
let tCalendar = createCalendarTable(calendars[i], elements);
});
}
}
)();
});