481 lines
17 KiB
JavaScript
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);
|
|
});
|
|
}
|
|
}
|
|
)();
|
|
|
|
});
|