547 lines
19 KiB
JavaScript
547 lines
19 KiB
JavaScript
// calendar.js
|
|
|
|
document.addEventListener('DOMContentLoaded', async function () {
|
|
const months_short = [0, 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'];
|
|
const weekdays = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstg', 'Freitag', 'Samstag', 'Sonntag'];
|
|
const url = '../DB4js.php';
|
|
const default_dauer = 90; // Standardführung dauert 90min
|
|
let fuehrungszeiten;
|
|
let isedit;
|
|
let entryInfo;
|
|
|
|
|
|
// Von der Datenbank Werte abholen
|
|
// Param:
|
|
// body: Object mit cmd und param
|
|
// Return:
|
|
// angeforderte Daten als JSON
|
|
const fetchFromDbase = async (body) => {
|
|
const response = await fetch(url, {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/js'},
|
|
body: JSON.stringify(body)
|
|
});
|
|
return await response.json();
|
|
}
|
|
|
|
|
|
// In die Datenbank Werte eintragen
|
|
// Param:
|
|
// body: Object mit cmd und param
|
|
// Return:
|
|
// angeforderte Daten als JSON
|
|
const putToDbase = async (body) => {
|
|
const response = await fetch(url, {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/js'},
|
|
body: JSON.stringify(body)
|
|
});
|
|
return await response.json();
|
|
}
|
|
|
|
|
|
// Die Daten der BEOs, die in einem Führungsteam sind, abholen
|
|
// Params: keine
|
|
// Retur:
|
|
// beos direkt gesetzt
|
|
async function getBEOs() {
|
|
let data = await fetchFromDbase({cmd: 'GET_BEOS', id: 'all', onlyguides: 'true'});
|
|
return data;
|
|
}
|
|
|
|
$('#versn').html("Version: " + VERSION + ' vom ' + VDATE)
|
|
|
|
let beos = await getBEOs();
|
|
|
|
|
|
// FullCalendar aufrufen und mit den Optionen versorgen
|
|
const calendarEl = document.getElementById('calendar');
|
|
let calendar = new FullCalendar.Calendar(calendarEl, {
|
|
themeSystem: 'bootstrap',
|
|
aspectRatio: 1.75,
|
|
locale: 'de',
|
|
editable: true,
|
|
selectable: true,
|
|
businessHours: {
|
|
daysOfWeek: [1, 2, 3, 4, 5],
|
|
startTime: '00:00',
|
|
endTime: '23.59'
|
|
},
|
|
nextDayThreshold: '00:30:00',
|
|
eventTimeFormat: {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
meridiem: false
|
|
},
|
|
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
|
|
customButtons: {
|
|
anleitButton: {
|
|
text: "Anleitung",
|
|
click: function() {
|
|
showAnleitung();
|
|
}
|
|
}
|
|
},
|
|
headerToolbar: {
|
|
start: 'anleitButton',
|
|
center: 'title',
|
|
end: 'today prev next'
|
|
},
|
|
firstDay: 1,
|
|
buttonText: {
|
|
today: 'heute'
|
|
},
|
|
dayMaxEvents: true, // allow "more" link when too many events
|
|
eventSources: [
|
|
{
|
|
events: async function (info, success, failure) {
|
|
try {
|
|
let fdates = await getFdates(info.start, info.end, beos);
|
|
success(fdates);
|
|
} catch (err) {
|
|
console.log("Fehler gekommen:", err);
|
|
failure(err);
|
|
}
|
|
},
|
|
color: '#e3e839',
|
|
borderColor: '#e3e839',
|
|
textColor: 'black',
|
|
},
|
|
{
|
|
events: async function (info, success, failure) {
|
|
try {
|
|
let fdates = getSundays(info.start);
|
|
success(fdates);
|
|
} catch (err) {
|
|
console.log("Fehler gekommen:", err);
|
|
failure(err);
|
|
}
|
|
},
|
|
color: '#e3e839',
|
|
borderColor: '#e3e839',
|
|
textColor: 'black',
|
|
},
|
|
{
|
|
events: async function (info, success, failure) {
|
|
try {
|
|
let fdates = await getCaldates(info.start, info.end);
|
|
success(fdates);
|
|
} catch (err) {
|
|
console.log("Fehler gekommen:", err);
|
|
failure(err);
|
|
}
|
|
},
|
|
},
|
|
{
|
|
events: async function (info, success, failure) {
|
|
try {
|
|
let fdates = await getHolidays(info.start, info.end);
|
|
success(fdates);
|
|
} catch (err) {
|
|
console.log("Fehler gekommen:", err);
|
|
failure(err);
|
|
}
|
|
},
|
|
color: '#AAA',
|
|
borderColor: '#AAA',
|
|
textColor: 'black',
|
|
}
|
|
],
|
|
eventDisplay: 'block',
|
|
dateClick: function (info) {
|
|
entryInfo = info.event;
|
|
console.log("Dateclick ausgeführt");
|
|
isedit = false;
|
|
fillModal(info.date, null);
|
|
$('#myModal .modal-title').text('Neuer Eintrag');
|
|
$('#myModal').modal();
|
|
},
|
|
/*
|
|
eventMouseEnter: async function (info) {
|
|
isedit = true;
|
|
entryInfo = info.event;
|
|
let start = entryInfo.start;
|
|
const holiday = await checkInHoliday(start);
|
|
if (holiday == -1) {
|
|
$(info.el).popover({
|
|
container: 'body',
|
|
title: entryInfo.title,
|
|
content: (entryInfo._def.extendedProps.description !== undefined) ? getFuehrungsInfo(entryInfo) : getRegularInfo(entryInfo),
|
|
trigger: 'hover',
|
|
placement: 'auto',
|
|
html: true
|
|
|
|
});
|
|
$(info.el).popover('show');
|
|
}
|
|
},
|
|
*/
|
|
eventClick: function (info) {
|
|
isedit = true;
|
|
entryInfo = info.event;
|
|
showViewModal(entryInfo);
|
|
},
|
|
});
|
|
// *** Ende der Kalender-optionen
|
|
|
|
calendar.render();
|
|
|
|
// ************
|
|
// Button-Event-Handler für die Dialog-Boxen
|
|
// ************
|
|
|
|
$('#btn_delete').click(function () {
|
|
btnDeleteClicked(true);
|
|
});
|
|
|
|
$('#btn_edit').click(function () {
|
|
btnEditClicked();
|
|
});
|
|
|
|
$('#btn_saveentry').click(function () {
|
|
btnSaveClicked();
|
|
});
|
|
|
|
|
|
// 'Speichern' geklicked:
|
|
async function btnSaveClicked() {
|
|
let ready = await saveEntry();
|
|
if (isedit && ready) {
|
|
await deleteEntry(entryInfo._def.publicId, false);
|
|
}
|
|
calendar.refetchEvents();
|
|
console.log("gelöscht bei Edit");
|
|
}
|
|
|
|
// 'Löschen' geklicked
|
|
async function btnDeleteClicked(abfrage) {
|
|
$('#viewModal').modal('hide');
|
|
await deleteEntry(entryInfo._def.publicId, abfrage);
|
|
}
|
|
|
|
async function deleteEntry(id, abfrage) {
|
|
if (abfrage) {
|
|
if (!confirm('Wirklich löschen?')) {
|
|
return;
|
|
}
|
|
}
|
|
// let event = calendar.getEventById(id);
|
|
// event.remove();
|
|
$('#txtTitle').val('');
|
|
$('#txtBeschr').val('');
|
|
let ret = await putToDbase({cmd: 'DEL_CALENTRY', id: id});
|
|
if (ret != true) {
|
|
alert(`Fehler beim Löschen des Eintrages !`);
|
|
}
|
|
calendar.refetchEvents();
|
|
}
|
|
|
|
|
|
// 'Ändern' geklicked:
|
|
async function btnEditClicked() {
|
|
$('#viewModal').modal('hide');
|
|
$('#myModal .modal-title').text('Eintrag ändern');
|
|
$('#myModal').modal();
|
|
fillModal(entryInfo.start, entryInfo.end);
|
|
console.log(entryInfo.title, entryInfo._def.extendedProps.description);
|
|
$('#txtTitle').val(entryInfo.title);
|
|
$('#txtBeschr').val(entryInfo._def.extendedProps.description);
|
|
}
|
|
|
|
|
|
// Reaktion auf den 'Sichern'-Knopf
|
|
// Den Eintrag zusammen bauen, dann in die Datenbank eintragen und das
|
|
// Fenster wieder löschen
|
|
const saveEntry = async () => {
|
|
if ($('#txtTitle').val() == '') {
|
|
alert("Es muss ein Titel eingebeben werden!");
|
|
return false;
|
|
}
|
|
let entry = {};
|
|
entry.title = $('#txtTitle').val();
|
|
entry.description = $('#txtBeschr').val();
|
|
entry.start = $('#st_date_year option:selected').text() + '-';
|
|
entry.start += $('#st_date_month option:selected').val() + '-';
|
|
entry.start += $('#st_date_day option:selected').text() + 'T';
|
|
entry.start += $('#st_date_hours option:selected').text() + ':';
|
|
entry.start += $('#st_date_minutes option:selected').text();
|
|
entry.end = $('#end_date_year option:selected').text() + '-';
|
|
entry.end += $('#end_date_month option:selected').val() + '-';
|
|
entry.end += $('#end_date_day option:selected').text() + 'T';
|
|
entry.end += $('#end_date_hours option:selected').text() + ':';
|
|
entry.end += $('#end_date_minutes option:selected').text();
|
|
if (!isedit) {
|
|
$('#txtTitle').val('');
|
|
$('#txtBeschr').val('');
|
|
}
|
|
$('#myModal').modal('hide');
|
|
let ret = await putToDbase({cmd: 'PUT_CALENTRY', data: entry});
|
|
return ret;
|
|
}
|
|
|
|
// ********************
|
|
// Ende Button-Event-Handler
|
|
// ********************
|
|
|
|
|
|
// Die Startzeit des dritten (der liegt gesichert im aktuellen Monat)
|
|
// Regelführungstermins des Monats finden
|
|
// Params:
|
|
// keine
|
|
// Return:
|
|
// entweder die Startzeit, falls gefunden oder aber 20 [Uhr]
|
|
function getFuehrungszeitZeit() {
|
|
if (fuehrungszeiten[3].start !== undefined) {
|
|
let st = moment(fuehrungszeiten[3].start);
|
|
return st.hour();
|
|
} else {
|
|
return 20;
|
|
}
|
|
}
|
|
|
|
|
|
// das Dialog-Fenster mit den Datums/Zeit-Optionen füllen
|
|
// Params:
|
|
// st_seldate gewähltes Startdatum
|
|
// end_seldate gewähltes Enddatum (oder leer => null)
|
|
// Return:
|
|
// nix
|
|
function fillModal(st_seldate, end_seldate) {
|
|
let start, end;
|
|
if (isedit) {
|
|
start = moment(st_seldate);
|
|
end = moment(end_seldate);
|
|
} else {
|
|
start = moment(st_seldate);
|
|
start.hour(getFuehrungszeitZeit());
|
|
end = moment(st_seldate);
|
|
end.hour(getFuehrungszeitZeit());
|
|
end = end.add(default_dauer, 'm');
|
|
$('#txtTitle').val('');
|
|
$('#txtBeschr').val('');
|
|
}
|
|
$('#st_date_day #end_date_day').html('');
|
|
$('#end_date_day').html('');
|
|
for (let i = 1; i <= 31; i++) {
|
|
$('#st_date_day').append(`<option ${start.date() == i ? 'selected' : ''}>${i}</option>`);
|
|
$('#end_date_day').append(`<option ${end.date() == i ? 'selected' : ''}>${i}</option>`);
|
|
}
|
|
$('#st_date_month #end_date_month').html('');
|
|
$('#end_date_month').html('');
|
|
for (let i = 1; i <= 12; i++) {
|
|
$('#st_date_month').append(`<option value=${i} ${(start.month() + 1) == i ? 'selected' : ''}>${months_short[i]}</option>`);
|
|
$('#end_date_month').append(`<option value=${i} ${(end.month() + 1) == i ? 'selected' : ''}>${months_short[i]}</option>`);
|
|
}
|
|
$('#st_date_year #end_date_year').html('');
|
|
$('#end_date_year').html('');
|
|
for (let i = 2020; i <= 2030; i++) {
|
|
$('#st_date_year').append(`<option ${start.year() == i ? 'selected' : ''}>${i}</option>`);
|
|
$('#end_date_year').append(`<option ${end.year() == i ? 'selected' : ''}>${i}</option>`);
|
|
}
|
|
$('#st_date_hours').html('');
|
|
$('#end_date_hours').html('');
|
|
for (let i = 0; i <= 23; i++) {
|
|
$('#st_date_hours').append(`<option ${start.hour() == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`);
|
|
$('#end_date_hours').append(`<option ${end.hour() == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`);
|
|
}
|
|
$('#st_date_minutes').html('');
|
|
$('#end_date_minutes').html('');
|
|
for (let i = 0; i <= 50; i += 10) {
|
|
$('#st_date_minutes').append(`<option ${start.minute() == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`);
|
|
$('#end_date_minutes').append(`<option ${end.minute() == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`);
|
|
}
|
|
}
|
|
|
|
// Aus der BEOs-Datenbank die namen und die Kürzel der
|
|
// für den übergebenen Führungstag aktiven BEOs
|
|
// Params:
|
|
// beos Array der Daten der BEOs
|
|
// data Objekt mit dem Führungstag
|
|
// Return:
|
|
// Objekt mit den Kürzeln und den Namen der aktiven BEOs
|
|
function checkGroupinBeos(beos, data) {
|
|
let kurz = "";
|
|
let name = "";
|
|
for (let b of beos) {
|
|
let grps = b.gruppe.split(',');
|
|
for (let i in grps) {
|
|
if (data.title == grps[i]) {
|
|
kurz += b.kürzel + ',';
|
|
name += `${b.vorname} ${b.name}<br />`;
|
|
}
|
|
}
|
|
}
|
|
return {k: kurz.slice(0, -1), n: name};
|
|
}
|
|
|
|
|
|
// Aus der Datenbank die Regel-Führungstage des Monat holen und die
|
|
// aktiven BEOs dazu eintragen
|
|
// Params:
|
|
// start Startdatum zu Suche in der DB
|
|
// end Endedatum dazu
|
|
// beos Array mit den BEOs daten
|
|
// Retur:
|
|
// Array mit den Regel-Führungszeiten des Monats mit den BEOs
|
|
async function getFdates(start, end, beos) {
|
|
// Zuerst die regelmäßigen Führungen hole
|
|
fuehrungszeiten = await fetchFromDbase({cmd: 'GET_FDATES', start: start, end: end});
|
|
for (let i = 0; i < fuehrungszeiten.length; i++) {
|
|
let start = moment(fuehrungszeiten[i].start);
|
|
start.add(fuehrungszeiten[i].uhr,'h')
|
|
fuehrungszeiten[i].start = moment(start).format()
|
|
let kurz = checkGroupinBeos(beos, fuehrungszeiten[i]);
|
|
if (kurz.k != "") {
|
|
fuehrungszeiten[i].title += " " + kurz.k;
|
|
fuehrungszeiten[i].namen = kurz.n;
|
|
}
|
|
}
|
|
return fuehrungszeiten;
|
|
}
|
|
|
|
// Aus der Datenbank die eingetragenen Führungen für den laufenden Monat holen
|
|
// Params:
|
|
// start, ende Start- und Endezeitpunk für die Suche in der DB
|
|
// Return:
|
|
// Array mit Führungen des laufenden Monats
|
|
async function getCaldates(start, end) {
|
|
return await fetchFromDbase({cmd: 'GET_CALENTRIES', start: start, end: end});
|
|
}
|
|
|
|
// Prüfen, ob das übergeben Datum in der Feiertags-Liste enthalten ist
|
|
// Params:
|
|
// date das zu prüfende Datum
|
|
//
|
|
// Return:
|
|
// true: das Datum ist ein Feiertag
|
|
// false: es ist keiner
|
|
async function checkInHoliday(date) {
|
|
const feiertage = await getHolidays(date)
|
|
let month = (date.getMonth()+1) <= 9 ? "0" + (date.getMonth()+1) : (date.getMonth()+1)
|
|
let day = date.getDate() <= 9 ? "0"+date.getDate() : date.getDate()
|
|
const datum = date.getFullYear() + '-' + month + "-" + day;
|
|
return feiertage.findIndex(x => x.start == datum);
|
|
}
|
|
|
|
|
|
// Die Feiertage in Baden-Württemberg von einer API via HTTP abholen
|
|
// Params:
|
|
// start, end Jahre, für das die Feiertage geholt werden
|
|
// ACHTUNG: es werden max. 2 Jahre geholt (start und end), da der
|
|
// Kalender max. 2 folgende Jahre anfordert.
|
|
// Return:
|
|
// Array mit den Feiertagen
|
|
async function getHolidays(start, end) {
|
|
let data = [];
|
|
let startyear = moment(start).year();
|
|
let endyear = moment(end).year();
|
|
let response = await fetch('https://feiertage-api.de/api/?jahr=' + startyear + '&nur_land=BW');
|
|
let holidays = await response.json();
|
|
for (const [k, v] of Object.entries(holidays)) {
|
|
if(k == "Ostermontag") {
|
|
data.push({start: moment(v.datum).subtract(1,'days').format("YYYY-MM-DD"), title: "Ostersonntag"});
|
|
}
|
|
if(k == "Pfingstmontag") {
|
|
data.push({start: moment(v.datum).subtract(1,'days').format("YYYY-MM-DD"), title: "Pfingstsonntag"});
|
|
}
|
|
data.push({start: v.datum, title: k});
|
|
}
|
|
if (startyear != endyear) {
|
|
let response = await fetch('https://feiertage-api.de/api/?jahr=' + endyear + '&nur_land=BW');
|
|
let holidays = await response.json();
|
|
for (const [k, v] of Object.entries(holidays)) {
|
|
data.push({start: v.datum, title: k});
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
// die ersten Sonntage des Monates im laufenden Jahr finden
|
|
// Params:
|
|
// year: das Jahr, für das die Sonntage gesucht werden
|
|
// Return:
|
|
// Array mit den Sonntagen
|
|
function getSundays(dt) {
|
|
let year = moment(dt).year();
|
|
const cm = moment(dt).month()
|
|
if (moment(dt).month() == 11) {
|
|
year += 1;
|
|
}
|
|
let data = [];
|
|
for (let i = 1; i <= 12; i++) {
|
|
let d = moment(year + '-' + i + '-01');
|
|
let w = d.isoWeekday();
|
|
let dt = ''
|
|
if (w == 7) {
|
|
dt = d.format('YYYY-MM-DD');
|
|
} else {
|
|
dt = d.add(7 - w, 'd').format('YYYY-MM-DD')
|
|
}
|
|
data.push({start: dt + 'T11:00:00', uhr: 11, title: 'Sonnenführung' })
|
|
}
|
|
return data;
|
|
}
|
|
|
|
|
|
// Anzeige des Dialogfensters zum Ändern/Löschen einer Führung
|
|
//
|
|
// Dieses Dialogfenster wird nur aufgerufen, wenn auf eine händisch
|
|
// eingetragene Führung geklickt wird (nicht bei Regeleführungen).
|
|
// Params:
|
|
// entryInfo Daten des geklickten Eintrages
|
|
// Return:
|
|
// nix
|
|
function showViewModal(entryInfo) {
|
|
let str
|
|
$('#viewModal .modal-title').text(entryInfo.title);
|
|
if (entryInfo._def.extendedProps.description !== undefined) { // Führungs-Eintrag
|
|
str = getFuehrungsInfo(entryInfo);
|
|
$('#btn_delete').show()
|
|
$('#btn_edit').show()
|
|
} else {
|
|
str = getRegularInfo(entryInfo)
|
|
$('#btn_delete').hide()
|
|
$('#btn_edit').hide()
|
|
}
|
|
$('#viewModal .viewdesc').html(str);
|
|
$('#viewModal').modal();
|
|
}
|
|
|
|
|
|
// Informationen einer Regelführung für das Popup zusammenbauen
|
|
function getRegularInfo(entryInfo) {
|
|
let curDate = moment(entryInfo.start).format('YYYYMMDD');
|
|
let besucher = entryInfo._def.extendedProps.count;
|
|
if (besucher == null) { besucher = "0"}
|
|
besucher = parseInt(besucher)
|
|
let wtg = moment(entryInfo.start).isoWeekday();
|
|
let nbr = entryInfo.title.split(' ');
|
|
let str = `<h6>${weekdays[wtg - 1]}s-Team ${nbr[1]}</h6>`;
|
|
str += `<div id="beonamen">${entryInfo._def.extendedProps.namen}</div>`;
|
|
let btxt = besucher != 0 ? `<strong>${besucher}</strong> angemeldete Besucher` : 'Keine Anmeldungen';
|
|
str += btxt;
|
|
str += `<br />Von ${moment(entryInfo.start).format("HH:mm")} Uhr bis: ${moment(entryInfo.start).add(default_dauer, 'm').format("HH:mm")} Uhr`;
|
|
return str;
|
|
}
|
|
|
|
|
|
// Informationen für eine händisch eingetragene Führung zusammenbauen.
|
|
// Wird bei dem Popup und bei dem Ändern/löschen verwendent
|
|
function getFuehrungsInfo(entryInfo) {
|
|
let str = entryInfo._def.extendedProps.description;
|
|
str += `<br /><br />Start: ${moment(entryInfo.start).format("YYYY-MM-DD HH:mm")} Uhr <br />Ende: ${moment(entryInfo.end).format("YYYY-MM-DD HH:mm")} Uhr`;
|
|
return str;
|
|
}
|
|
|
|
|
|
function showAnleitung() {
|
|
console.log("Anleitung geklicked");
|
|
$('.viewAnleitung').load("docs/Anleitung.html",function() {
|
|
$('#infoModal').modal({show:true, focus:true});
|
|
});
|
|
};
|
|
|
|
|
|
}); // Ende document.addEventListener()
|
|
|