// 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(``); $('#end_date_day').append(``); } $('#st_date_month #end_date_month').html(''); $('#end_date_month').html(''); for (let i = 1; i <= 12; i++) { $('#st_date_month').append(``); $('#end_date_month').append(``); } $('#st_date_year #end_date_year').html(''); $('#end_date_year').html(''); for (let i = 2020; i <= 2030; i++) { $('#st_date_year').append(``); $('#end_date_year').append(``); } $('#st_date_hours').html(''); $('#end_date_hours').html(''); for (let i = 0; i <= 23; i++) { $('#st_date_hours').append(``); $('#end_date_hours').append(``); } $('#st_date_minutes').html(''); $('#end_date_minutes').html(''); for (let i = 0; i <= 50; i += 10) { $('#st_date_minutes').append(``); $('#end_date_minutes').append(``); } } // 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}
`; } } } 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 = `
${weekdays[wtg - 1]}s-Team ${nbr[1]}
`; str += `
${entryInfo._def.extendedProps.namen}
`; let btxt = besucher != 0 ? `${besucher} angemeldete Besucher` : 'Keine Anmeldungen'; str += btxt; str += `
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 += `

Start: ${moment(entryInfo.start).format("YYYY-MM-DD HH:mm")} Uhr
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()