From e5355e7626ea11ef55de9016452f00135baac579 Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Thu, 9 Jan 2020 20:10:59 +0100 Subject: [PATCH 01/18] Edited event loading --- widgets/calendar.html | 221 +++++++++++++++++++++++++++--------------- 1 file changed, 142 insertions(+), 79 deletions(-) diff --git a/widgets/calendar.html b/widgets/calendar.html index 1cf4ab4..d905c19 100644 --- a/widgets/calendar.html +++ b/widgets/calendar.html @@ -101,9 +101,10 @@ --> - + \ No newline at end of file + <% renderPage(that.data.attr('oid'), data);%> + <% setTimeout(function () {iniCalendar(that.data.attr('wid')); setReturnModus(0);}, 100); %> + + + \ No newline at end of file From 5fb23d4e4418131948d693579e327c6f29454804 Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Fri, 10 Jan 2020 22:10:23 +0100 Subject: [PATCH 04/18] Added some rules --- widgets/calendar/css/style.css | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/widgets/calendar/css/style.css b/widgets/calendar/css/style.css index 06bdfce..33aac51 100644 --- a/widgets/calendar/css/style.css +++ b/widgets/calendar/css/style.css @@ -98,6 +98,28 @@ overflow: hidden; } +.calendar-event-table { + width: 100%; + margin-top: 1em; + margin-bottom: 1em; +} + +.calendar-event-table-big { + width: 100%; + table-layout: fixed; + padding: 0.5em; +} + +.calendar-event-detail { + background-color: #dfdfdf; + font-weight: bold; + line-height: 16px; + border-radius: 3px; + margin: 2px; + overflow: hidden; + box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12); +} + .calendar-entry-detail { background-color: inherit; position: fixed; From 3086ce634ede43f4486936aa82fd157d24cebdbe Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Fri, 10 Jan 2020 22:10:55 +0100 Subject: [PATCH 05/18] Added date detail popup --- widgets/calendar.html | 90 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/widgets/calendar.html b/widgets/calendar.html index e2db703..dfc3224 100644 --- a/widgets/calendar.html +++ b/widgets/calendar.html @@ -153,6 +153,10 @@ for(let i = 0; i < ids.length; i++) { + let isInMap = false; + + //for(let k = 0; k < events.size) + ids[i].loaded = await new Promise((resolve, reject) => { vis.conn.getStates(ids[i].id + '*', function (err, states) { @@ -205,7 +209,6 @@ const calendarEvents = document.getElementsByClassName(wid + '-calendar-event'); for (let k = 0; k < calendarEvents.length; k++) { - console.log(wid + " " + color.get(calendarEvents[k].getAttribute('calid')) + " " + calendarEvents[k].getAttribute('calid')); calendarEvents[k].style.backgroundColor = color.get(calendarEvents[k].getAttribute('calid')); } } @@ -388,10 +391,93 @@ calendarEntryDetailContainer.children[0].children[0].innerHTML = ((d.getDate() < 10) ? '0' + d.getDate() : d.getDate()) + '.' + ((d.getMonth() + 1 < 10) ? '0' + (d.getMonth() + 1) : d.getMonth() + 1) + '.' + d.getFullYear(); + + let table = document.getElementById(wid + '-calendar-entry-detail-table'); + + table.innerHTML = createTableContent(wid, d.getFullYear(), d.getMonth(), d.getDate()); if(calendarEntryDetailContainer.classList.contains('calendar-entry-detail-hidden')) calendarEntryDetailContainer.classList.remove('calendar-entry-detail-hidden'); } + function createTableContent(wid, y, m ,d) { + + const template = + '' + + '' + + '
' + + '' + + '' + + ' ' + + ' ' + + '' + + '' + + ' ' + + '' + + '
##time####summary##
##description##
' + + '
' + + '' + + ''; + + y = parseInt(y); + m = parseInt(m); + d = parseInt(d); + + //Monate fangen bei 0 an zuzählen + m++; + + m = (m < 10) ? '0' + m : m; + d = (d < 10) ? '0' + d : d; + + const map = events.get(wid); + + const dayObj = map.get(y + '-' + m + '-' + d); + + let newTableContent = ''; + + if(dayObj) { + const eventObj = dayObj.events; + + if(eventObj.length > 0) { + + for(let j = 0; j < eventObj.length; j++) { + + let newEntry = template; + + const startTime = new Date(eventObj[j].startTime); + const endTime = new Date(eventObj[j].endTime); + + if(!eventObj[j].startTime.includes('T')) { + startTime.setHours(0); + startTime.setHours(0); + startTime.setHours(0); + } + + if(!eventObj[j].endTime.includes('T')) { + endTime.setHours(0); + endTime.setHours(0); + endTime.setHours(0); + } + + const startTimeText = ((startTime.getHours() < 10) ? '0' + startTime.getHours() : startTime.getHours()) + ':' + + ((startTime.getMinutes() < 10) ? '0' + startTime.getMinutes() : startTime.getMinutes()); + const endTimeText = ((endTime.getHours() < 10) ? '0' + endTime.getHours() : endTime.getHours()) + ':' + + ((endTime.getMinutes() < 10) ? '0' + endTime.getMinutes() : endTime.getMinutes()); + + newEntry = newEntry.replace('##summary##', eventObj[j].summary); + newEntry = newEntry.replace('##time##', startTimeText + ' - ' + endTimeText); + newEntry = newEntry.replace('##description##', (eventObj[j].description || '')); + newEntry = newEntry.replace('##background-color##', color.get(eventObj[j].id)); + + newTableContent = newTableContent + newEntry; + } + } + } + + console.log("Inhalt: " + newTableContent); + + return newTableContent; + } + function closeDateDetails(wid) { let calendarEntryDetailContainer = document.getElementById(wid + '-calendar-entry-detail-container'); @@ -543,6 +629,8 @@

+ +
CLOSE
From 352bb6270624e45ea70697bb8e61b3d889332d2a Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Fri, 10 Jan 2020 22:12:04 +0100 Subject: [PATCH 06/18] Added functions in calendar.js --- widgets/calendar/js/calendar.js | 330 +++++++++++++++++++++++++++++++- 1 file changed, 322 insertions(+), 8 deletions(-) diff --git a/widgets/calendar/js/calendar.js b/widgets/calendar/js/calendar.js index 769e9a5..04b2a29 100644 --- a/widgets/calendar/js/calendar.js +++ b/widgets/calendar/js/calendar.js @@ -1,7 +1,7 @@ /* ioBroker.vis template Widget-Set - version: "0.0.1" + version: '0.0.1' Copyright 2019 Author author@mail.com */ @@ -14,8 +14,322 @@ $.get( 'adapter/template/words.js', function(script) { $.extend(systemDictionary, JSON.parse(translation)); }); +vis.binds.calendar = { + initCalendar: function(wid) { + const events = new Map(); + let date_memory; + let color; + let isLoaded = false; + let returnModus = 0; + + const d = new Date(); + + renderPage(wid); + setDateToMemory(d); + loadCalendar(wid); + + function renderPage(wid) { + vis.conn.getStates(wid + '*', function (err, states) { + + for(const state in states) { + + if(state.endsWith('events')) { + + const eventsObj = JSON.parse(states[state].val); + const dayObj = {}; + const date = states[state.replace('.events', '') + '.date'].val; + + dayObj.events = eventsObj; + + events.set(date, dayObj); + + } else if(state.endsWith('color')) { + + color = states[state].val; + } + } + + isLoaded = true; + }); + } + + function colorizeEvents(color) { + const calendarEvents = document.getElementsByClassName('calendar-event'); + + for (let k = 0; k < calendarEvents.length; k++) { + calendarEvents[k].style.backgroundColor = color; + } + } + + async function loadCalendar(wid) { + //aktuelles Datum holen (1. des Monats) + let d = getDateFromMemory(); + //Monat ermitteln aus this_date (zählen beginnt bei 0, daher +1) + let m = d.getMonth(); + //Jahr ermitteln aus this_date (YYYY) + let y = d.getFullYear(); + //Monat und Jahr eintragen + //document.all.calendar_month.innerHTML = getMonthname(m+1) + ' ' + y; + document.getElementById(wid + '-calendar-month').innerHTML = getMonthname(m + 1) + ' ' + y; + + //ersten Tag des Monats festlegen + let firstD = d; + firstD.setDate(1); + //Wochentag ermitteln vom 1. des übergebenen Monats (Wochentag aus firstD) + let dateDay = firstD.getDay(); //So = 0, Mo = 1 … Sa = 6 + //Sonntag soll den Wert 7 darstellen -> Mo = 1 … So = 7 + dateDay = (dateDay == 0) ? 7: dateDay; + //Speicher für aktuelle Zelle + let entry = ''; + //Speicher für aktuellen Tag + let zahl = ''; + //heutiges Datum ermitteln + let hD = new Date(); + //ist event + //falls event, dann darf der Rahmen + //nicht vom isHolyday überschrieben werden + let bEvent = false; + + //Alle Kalender Spalten durchzählen + for (let i = 1; i <= 42; i++) { + bEvent = false; + + //holen der aktuellen Zelle + entry = document.getElementById(wid + '-calendar-entry-' + i); + //errechnen der Tages Zahl + zahl = (i + 1) - dateDay; + //datum zusammenschreiben + let dx = new Date(y, m, zahl); + + //Eintragen der Daten ab ersten Tag im Monat und wenn es ein gültiges Datum ist + if (i >= dateDay && isValidDate(y, m, zahl)) { + + entry.innerHTML = '
' + zahl + '
'; + + if(entry.classList.contains('calendar-entry-invisible')) entry.classList.remove('calendar-entry-invisible'); + + //Listener hinzufügen + entry.onclick = function(event) { + openDateDetails(wid, event.currentTarget.children[0].innerHTML) + }; + + //heutiges Datum hervorheben + if (hD.getDate() == dx.getDate() && + hD.getMonth() == dx.getMonth() && + hD.getYear() == dx.getYear()) { + if(!entry.classList.contains('calendar-entry-today')) entry.classList.add('calendar-entry-today'); + } else { + if(entry.classList.contains('calendar-entry-today')) entry.classList.remove('calendar-entry-today'); + } + + //Events hinzufügen + do { + if(isLoaded) { + entry.appendChild(getEvents(y, m, zahl)); + } else { + await sleep(100); + } + + } while(isLoaded == false); + + //Events einfärben + colorizeEvents(color); + } else { + + entry.innerHTML = ''; + + if(i >= dateDay) {//Wenn Kalenderende + + if(!entry.classList.contains('calendar-entry-invisible')) entry.classList.add('calendar-entry-invisible'); + + } else {//Wenn Kalenderanfang + + if(!entry.classList.contains('calendar-entry-invisible')) entry.classList.add('calendar-entry-invisible'); + } + } + } + } + + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + function nextMonth() { + let d = getDateFromMemory(); + let m = d.getMonth() + 1; + let y = d.getFullYear(); + + //Falls Jahres wechsel + if((m + 1) > 12) { + m = 0; + y = y + 1; + } + + d = new Date(y, m, 1); + setDateToMemory(d); + loadCalendar(); + } + + function prevMonth() { + let d = getDateFromMemory(); + let m = d.getMonth()+1; + let y = d.getFullYear(); + + //Falls Jahres1wechsel + if((m-1) < 1) { + m = 11; + y = y - 1; + } else { + m = m - 2; + } + + d = new Date(y, m, 1); + setDateToMemory(d); + loadCalendar(); + } + + function isValidDate(y, m, d) { + //–Gibt Datum des letzten Tag des Monats aus– + let thisDate = new Date(y, m, 1); + //einen Tag weiter schalten + thisDate.setMonth(thisDate.getMonth() + 1); + //vom ersten Tag des nächsten monats + //ein Tag abziehen + thisDate.setTime(thisDate.getTime() - 12*3600*1000) + + if(d > thisDate.getDate()) { + return false; + } else { + return true; + } + } + + function setDateToMemory(d) { + //document.getElementById('date_memory').innerHTML = d.getFullYear() + ',' + (d.getMonth() + 1) + ',' + d.getDate(); + date_memory = d.getFullYear() + ',' + (d.getMonth() + 1) + ',' + d.getDate(); + } + + function getDateFromMemory() { + //var s = document.getElementById('date_memory').innerHTML; + let s = date_memory; + let z = s.split(','); + return new Date(z[0], z[1] - 1, z[2]); + } + + function getMonthname(monthnumber) { + switch(monthnumber) { + case 1: return 'Januar'; + case 2: return 'Februar'; + case 3: return 'März'; + case 4: return 'April'; + case 5: return 'Mai'; + case 6: return 'Juni'; + case 7: return 'Juli'; + case 8: return 'August'; + case 9: return 'September'; + case 10: return 'Oktober'; + case 11: return 'November'; + case 12: return 'Dezember'; + default: return '-'; + } + } + + function openDateDetails(wid, n) { + + let d = getDateFromMemory(); + d.setDate(n); + + let calendarEntryDetailContainer = document.getElementById(wid + '-calendar-entry-detail-container'); + + calendarEntryDetailContainer.children[0].children[0].innerHTML = ((d.getDate() < 10) ? '0' + d.getDate() : d.getDate()) + '.' + + ((d.getMonth() + 1 < 10) ? '0' + (d.getMonth() + 1) : d.getMonth() + 1) + '.' + d.getFullYear(); + + if(calendarEntryDetailContainer.classList.contains('calendar-entry-detail-hidden')) calendarEntryDetailContainer.classList.remove('calendar-entry-detail-hidden'); + } + + function closeDateDetails() { + + let calendarEntryDetailContainer = document.getElementById('calendar-entry-detail-container'); + + if(!calendarEntryDetailContainer.classList.contains('calendar-entry-detail-hidden')) calendarEntryDetailContainer.classList.add('calendar-entry-detail-hidden'); + } + + function isHoliday(m,d) { + //Monate fangen bei 0 an zuzählen + m++; + //festlegen der Feiertage + let h = new Array(7); + + h[0] = '1.1'; + h[1] = '6.1'; + h[2] = '1.5'; + h[3] = '3.10'; + h[4] = '1.11'; + h[5] = '25.12'; + h[6] = '26.12'; + h[7] = '31.12'; + + let iD; + //Alle Daten Testen + for ( var i = 0; i < h.length; i++) { + iH = h[i].split('.'); + if (iH[0] == d && iH[1] == m) { + return true; + } + } + //Wenn kein Feiertag gefunden + return false; + } + + function setReturnModus(returnIndex) { + returnModus = returnIndex; + } + + function getEvents(y, m, d) { + //convertieren in int-Zahlen + y = parseInt(y); + m = parseInt(m); + d = parseInt(d); + + //Monate fangen bei 0 an zuzählen + m++; + + m = (m < 10) ? '0' + m : m; + d = (d < 10) ? '0' + d : d; + + const dayObj = events.get(y + '-' + m + '-' + d); + + if(dayObj) { + const eventObj = dayObj.events; + + if(eventObj.length > 0) { + + const nodeEvents = document.createElement('div'); + nodeEvents.classList.add('calendar-event-container'); + + for(let j = 0; j < eventObj.length; j++) { + + const element = document.createElement('div'); + element.classList.add('calendar-event'); + + const text = document.createTextNode(eventObj[j].summary); + + element.appendChild(text); + + nodeEvents.appendChild(element); + } + + return nodeEvents; + } + } + + return document.createTextNode(''); + } + } +}; + // this code can be placed directly in template.html -vis.binds['template'] = { +/*vis.binds['template'] = { version: '0.0.1', showVersion: function () { if (vis.binds['template'].version) { @@ -24,7 +338,7 @@ vis.binds['template'] = { } }, createWidget: function (widgetID, view, data, style) { - var $div = $('#' + widgetID); + let $div = $('#' + widgetID); // if nothing found => wait if (!$div.length) { return setTimeout(function () { @@ -32,13 +346,13 @@ vis.binds['template'] = { }, 100); } - var text = ''; + let text = ''; text += 'OID: ' + data.oid + '
'; - text += 'OID value: ' + vis.states[data.oid + '.val'] + '
'; - text += 'Color: ' + data.myColor + '
'; + text += 'OID value: ' + vis.states[data.oid + '.val'] + '
'; + text += 'Color: ' + data.myColor + '
'; text += 'extraAttr: ' + data.extraAttr + '
'; text += 'Browser instance: ' + vis.instance + '
'; - text += 'htmlText:
'; + text += 'htmlText:
'; $('#' + widgetID).html(text); @@ -51,4 +365,4 @@ vis.binds['template'] = { } }; -vis.binds['template'].showVersion(); \ No newline at end of file +//vis.binds['template'].showVersion();*/ \ No newline at end of file From 5dbaa2ce5e9523b768101e1adccdfb1e05cecd8e Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Fri, 10 Jan 2020 23:39:43 +0100 Subject: [PATCH 07/18] Added some color setting --- widgets/calendar.html | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/widgets/calendar.html b/widgets/calendar.html index dfc3224..79aeb60 100644 --- a/widgets/calendar.html +++ b/widgets/calendar.html @@ -110,7 +110,10 @@ "dayColor": {"en": "weekday color", "de": "Wochentagsfarbe","ru": "цвет дня недели"}, "dateColor": {"en": "date color", "de": "Datumsfarbe", "ru": "цвет даты"}, "dateBackgroundColor": {"en": "date background color", "de": "Datumshintergrundfarbe", "ru": "цвет фона даты"}, - "group_calendar": {"en": "calendar", "de": "Kalender", "ru": "календарь"} + "group_calendar": {"en": "additional calendars", "de": "zusätzliche Kalender", "ru": "дополнительные календари"}, + "eventTextColor": {"en": "event text color", "de": "Ereignistextfarbe", "ru": "цвет текста события"}, + "popupColor": {"en": "popup color", "de": "Popup-Farbe", "ru": "всплывающий цвет"}, + "popupCloseColor": {"en": "close button color", "de": "Farbe der Schaltfläche \"Schließen\"", "ru": "цвет кнопки закрытия"} }); } @@ -132,7 +135,7 @@ let ids = []; - ids.push({id: oid, loaded: false}); + ids.push({id: oid, color: data.attr('eventTextColor'), loaded: false}); for(let i = 0; i <= data.count; i++) { if(data.attr('oid' + i)) { @@ -145,7 +148,7 @@ } } - if(!isInList) ids.push({id: data.attr('oid' + i), loaded: false}); + if(!isInList) ids.push({id: data.attr('oid' + i), color: data.attr('eventTextColor' + i), loaded: false}); } } @@ -182,7 +185,7 @@ } else if(state.endsWith('color')) { - color.set(ids[i].id, states[state].val); + color.set(ids[i].id, {backgroundColor: states[state].val, color: ids[i].color}); } } @@ -209,7 +212,12 @@ const calendarEvents = document.getElementsByClassName(wid + '-calendar-event'); for (let k = 0; k < calendarEvents.length; k++) { - calendarEvents[k].style.backgroundColor = color.get(calendarEvents[k].getAttribute('calid')); + + let colors = color.get(calendarEvents[k].getAttribute('calid')); + + calendarEvents[k].style.backgroundColor = colors.backgroundColor; + calendarEvents[k].style.color = colors.color; + } } @@ -404,7 +412,7 @@ const template = '' + '' + - '
' + + '
' + '' + '' + ' ' + @@ -463,17 +471,18 @@ const endTimeText = ((endTime.getHours() < 10) ? '0' + endTime.getHours() : endTime.getHours()) + ':' + ((endTime.getMinutes() < 10) ? '0' + endTime.getMinutes() : endTime.getMinutes()); + const colors = color.get(eventObj[j].id); + newEntry = newEntry.replace('##summary##', eventObj[j].summary); newEntry = newEntry.replace('##time##', startTimeText + ' - ' + endTimeText); newEntry = newEntry.replace('##description##', (eventObj[j].description || '')); - newEntry = newEntry.replace('##background-color##', color.get(eventObj[j].id)); + newEntry = newEntry.replace('##background-color##', colors.backgroundColor); + newEntry = newEntry.replace('##color##', colors.color); newTableContent = newTableContent + newEntry; } } } - - console.log("Inhalt: " + newTableContent); return newTableContent; } @@ -541,9 +550,9 @@ type="text/ejs" class="vis-tpl" data-vis-prev='' - data-vis-attrs="oid/id;count[1]/slider,1,5,1;" - data-vis-attrs0="group.color;monthYearColor/color;buttonColor/color;dayColor/color;dateColor/color;dateBackgroundColor/color;" - data-vis-attrs1="group.calendar/byindex;oid(1-count)/id;" + data-vis-attrs="oid/id;eventTextColor/color;count[0]/slider,0,5,0;" + data-vis-attrs0="group.color;monthYearColor/color;buttonColor/color;dayColor/color;dateColor/color;dateBackgroundColor/color;popupColor/color;popupCloseColor/color;" + data-vis-attrs1="group.calendar/byindex;oid(1-count)/id;eventTextColor(1-count)/color;" data-vis-set="calendar" data-vis-type="calendar" data-vis-name="Calendar"> @@ -626,12 +635,12 @@
##time##
-
+

- CLOSE + CLOSE
From 572c1449c38d7141536776b3e38ae3c6722c2d2a Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Fri, 10 Jan 2020 23:44:22 +0100 Subject: [PATCH 08/18] Added some color setting --- widgets/calendar.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/widgets/calendar.html b/widgets/calendar.html index 79aeb60..710a909 100644 --- a/widgets/calendar.html +++ b/widgets/calendar.html @@ -113,7 +113,8 @@ "group_calendar": {"en": "additional calendars", "de": "zusätzliche Kalender", "ru": "дополнительные календари"}, "eventTextColor": {"en": "event text color", "de": "Ereignistextfarbe", "ru": "цвет текста события"}, "popupColor": {"en": "popup color", "de": "Popup-Farbe", "ru": "всплывающий цвет"}, - "popupCloseColor": {"en": "close button color", "de": "Farbe der Schaltfläche \"Schließen\"", "ru": "цвет кнопки закрытия"} + "popupCloseColor": {"en": "close button color", "de": "Farbe der Schaltfläche \"Schließen\"", "ru": "цвет кнопки закрытия"}, + "popupBackgroundColor": {"en": "popup background color", "de": "Popup-Hintergrundfarbe", "ru": "всплывающий цвет фона"}, }); } @@ -551,7 +552,7 @@ class="vis-tpl" data-vis-prev='' data-vis-attrs="oid/id;eventTextColor/color;count[0]/slider,0,5,0;" - data-vis-attrs0="group.color;monthYearColor/color;buttonColor/color;dayColor/color;dateColor/color;dateBackgroundColor/color;popupColor/color;popupCloseColor/color;" + data-vis-attrs0="group.color;monthYearColor/color;buttonColor/color;dayColor/color;dateColor/color;dateBackgroundColor/color;popupColor/color;popupBackgroundColor/color;popupCloseColor/color;" data-vis-attrs1="group.calendar/byindex;oid(1-count)/id;eventTextColor(1-count)/color;" data-vis-set="calendar" data-vis-type="calendar" @@ -636,7 +637,7 @@
-
+

From e70e6c112597824e93854da885d755298cbb118c Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Fri, 10 Jan 2020 23:55:55 +0100 Subject: [PATCH 09/18] Fixed slider --- widgets/calendar.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/widgets/calendar.html b/widgets/calendar.html index 710a909..53e9e72 100644 --- a/widgets/calendar.html +++ b/widgets/calendar.html @@ -551,12 +551,13 @@ type="text/ejs" class="vis-tpl" data-vis-prev='' - data-vis-attrs="oid/id;eventTextColor/color;count[0]/slider,0,5,0;" + data-vis-attrs="oid/id;eventTextColor/color;count[0]/slider,0,5,1;" data-vis-attrs0="group.color;monthYearColor/color;buttonColor/color;dayColor/color;dateColor/color;dateBackgroundColor/color;popupColor/color;popupBackgroundColor/color;popupCloseColor/color;" data-vis-attrs1="group.calendar/byindex;oid(1-count)/id;eventTextColor(1-count)/color;" data-vis-set="calendar" data-vis-type="calendar" - data-vis-name="Calendar"> + data-vis-name="Calendar" + data-vis-update-style="true">
From ddb7b66457e4c01fb18cb4680e6c2c83fd5ba204 Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Sat, 11 Jan 2020 22:12:27 +0100 Subject: [PATCH 10/18] Updated dependencies --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4990fc9..7712635 100644 --- a/package.json +++ b/package.json @@ -20,9 +20,10 @@ }, "dependencies": { "@iobroker/adapter-core": "^2.1.0", - "express": "^4.13.3", + "express": "^4.17.1", "googleapis": "^46.0.0", - "node-cron": "^2.0.3" + "node-cron": "^2.0.3", + "xml2js": "^0.4.23" }, "devDependencies": { "@iobroker/testing": "^1.3.0", From 4db1c213051eb0b99b8f510e72077740db54c725 Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Sat, 11 Jan 2020 22:29:47 +0100 Subject: [PATCH 11/18] Added ical parser --- lib/ical.js | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 lib/ical.js diff --git a/lib/ical.js b/lib/ical.js new file mode 100644 index 0000000..1c094f6 --- /dev/null +++ b/lib/ical.js @@ -0,0 +1,91 @@ +/** + * Parse iCal to Json. + * @param {string} data iCal data + * @returns {Object} Object + */ +function parse(data) { + + const object = {}; + + const dataList = data.split((data.includes('\r\n')) ? '\r\n' : (data.includes('\n')) ? '\n' : '\r'); + + for(let i = 0; i < dataList.length; i++) { + + let dataLine = dataList[i].split(':'); + + if(dataList[i].startsWith('PRODID')) object.prodid = dataLine[1]; + if(dataList[i].startsWith('VERSION')) object.version = dataLine[1]; + if(dataList[i].startsWith('CALSCALE')) object.calscale = dataLine[1]; + if(dataList[i].startsWith('METHOD')) object.method = dataLine[1]; + + if(dataList[i].startsWith('BEGIN:VEVENT')) { + + const event = {}; + + do { + i++; + + dataLine = dataList[i].split(':'); + + if(dataList[i].startsWith('CREATED')) event.created = dataLine[1]; + if(dataList[i].startsWith('DTSTAMP')) event.dtstamp = dataLine[1]; + if(dataList[i].startsWith('LAST-MODIFIED')) event.lastModified = dataLine[1]; + if(dataList[i].startsWith('UID')) event.uid = dataLine[1]; + if(dataList[i].startsWith('SUMMARY')) event.summary = dataLine[1]; + if(dataList[i].startsWith('CLASS')) event.class = dataLine[1]; + if(dataList[i].startsWith('DESCRIPTION')) event.description = dataLine[1]; + if(dataList[i].startsWith('LOCATION')) event.location = dataLine[1]; + if(dataList[i].startsWith('SEQUENCE')) event.sequence = dataLine[1]; + if(dataList[i].startsWith('STATUS')) event.status = dataLine[1]; + if(dataList[i].startsWith('TRANSP')) event.transp = dataLine[1]; + + if(dataList[i].startsWith('DTSTART')) { + + const dtstart = {}; + + if(dataLine[0].includes(';')) { + + const dtstartLine = dataLine[0].split(';'); + + if(dtstartLine[1].startsWith('TZID')) dtstart.tzid = dtstartLine[1].split('=')[1]; + if(dtstartLine[1].startsWith('VALUE')) dtstart.value = dtstartLine[1].split('=')[1]; + + } + + dtstart.val = dataLine[1]; + + event.dtstart = dtstart; + } + + if(dataList[i].startsWith('DTEND')) { + + const dtend = {}; + + if(dataLine[0].includes(';')) { + + const dtendLine = dataLine[0].split(';'); + + if(dtendLine[1].startsWith('TZID')) dtend.tzid = dtendLine[1].split('=')[1]; + if(dtendLine[1].startsWith('VALUE')) dtend.value = dtendLine[1].split('=')[1]; + } + + dtend.val = dataLine[1]; + + event.dtend = dtend; + } + + } while(!dataList[i].startsWith('END:VEVENT')); + + if(!object.events) object.events = []; + + object.events.push(event); + } + + } + + return object; +} + +module.exports = { + parse +}; \ No newline at end of file From a2098efa2a42bc5bb1b8180ba8cc75e3845ddd1b Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Sat, 11 Jan 2020 22:30:09 +0100 Subject: [PATCH 12/18] Added util --- lib/utils.js | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 lib/utils.js diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..032f6bb --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,59 @@ +/** + * Parse iCal to Json. + * @param {string} summary + * @param {string} description + * @param {string} startTime + * @param {string} endTime + * @returns {Object} + */ +function normalizeEvent(summary, description, startTime, endTime) { + + const object = {}; + + object.summary = summary; + object.description = description; + + if(startTime.includes('-')) { + object.startTime = startTime; + } else { + if(startTime.includes('T')) { + + const tmp = startTime.split('T'); + + const date = `${tmp[0].substring(0, 4)}-${tmp[0].substring(4, 6)}-${tmp[0].substring(6, 8)}`; + const time = `${tmp[1].substring(0, 2)}:${tmp[1].substring(2, 4)}:${tmp[1].substring(4, 6)}`; + + object.startTime = `${date}T${time}`; + } else { + + const date = `${startTime.substring(0, 4)}-${startTime.substring(4, 6)}-${startTime.substring(6, 8)}`; + + object.startTime = date; + } + } + + if(endTime.includes('-')) { + object.endTime = endTime; + } else { + if(endTime.includes('T')) { + + const tmp = endTime.split('T'); + + const date = `${tmp[0].substring(0, 4)}-${tmp[0].substring(4, 6)}-${tmp[0].substring(6, 8)}`; + const time = `${tmp[1].substring(0, 2)}:${tmp[1].substring(2, 4)}:${tmp[1].substring(4, 6)}`; + + object.endTime = `${date}T${time}`; + } else { + + const date = `${endTime.substring(0, 4)}-${endTime.substring(4, 6)}-${endTime.substring(6, 8)}`; + + object.endTime = date; + } + } + + return object; +} + +module.exports = { + normalizeEvent +}; \ No newline at end of file From 376ab38ae598999317a94f787f4861f9c15f70e9 Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Sat, 11 Jan 2020 22:30:30 +0100 Subject: [PATCH 13/18] Added nexcloud connection --- lib/nextcloud.js | 124 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 lib/nextcloud.js diff --git a/lib/nextcloud.js b/lib/nextcloud.js new file mode 100644 index 0000000..5cc8568 --- /dev/null +++ b/lib/nextcloud.js @@ -0,0 +1,124 @@ +const request = require('request'); +const xml2js = require('xml2js'); + +/** + * Get the contact list. + * @param {string} host The host of the Nexcloud server like https://nextcloud.example.com + * @param {string} username Username of the Nextcloud account + * @param {string} password Password of the Nextcloud account + * @returns {Promise} Object + */ +async function queryCalendarList(host, username, password) { + + const path = '/remote.php/dav/calendars/' + username; + const url = host + path; + + const auth = 'Basic ' + new Buffer(username + ':' + password).toString('base64'); + + const options = { + url: url, + method: 'PROPFIND', + headers: { + 'Authorization' : auth, + }, + body: ` + + + + + + + ` + }; + + return new Promise(function (resolve, reject) { + + request(options, (error, response, body) => { + + if(!error && (response.statusCode == 200 || response.statusCode == 207)) { + + const parser = new xml2js.Parser(); + + parser.parseString(body, function (err, result) { + + if(err) { + reject(err); + } else { + + const response = JSON.parse(JSON.stringify(result).replace(/d:/g, '').replace(/xmlns:/g, '').replace(/cs:/g, '').replace(/x1:/g, '')).multistatus.response; + + resolve(response); + } + }); + + } else { + reject(error); + } + }); + }); +} + +/** + * Get the event list. + * @param {string} host The host of the Nexcloud server like https://nextcloud.example.com + * @param {string} path The path to the calendar path + * @param {string} username Username of the Nextcloud account + * @param {string} password Password of the Nextcloud account + * @returns {Promise} Object + */ +async function queryEvents(host, path, username, password) { + + const url = host + path; + + const auth = 'Basic ' + new Buffer(username + ':' + password).toString('base64'); + + const options = { + url: url, + method: 'REPORT', + headers: { + 'Authorization' : auth, + 'Depth': 1 + }, + body: ` + + + + + + + + + + ` + }; + + return new Promise(function (resolve, reject) { + + request(options, (error, response, body) => { + if (!error && (response.statusCode == 200 || response.statusCode == 207)) { + + const parser = new xml2js.Parser(); + + parser.parseString(body, function (err, result) { + + if(err) { + reject(err); + } else { + + const response = JSON.parse(JSON.stringify(result).replace(/d:/g, '').replace(/xmlns:/g, '').replace(/cal:/g, '').replace(/\\"/g, '')).multistatus.response; + + resolve(response); + } + }); + + } else { + reject(error); + } + }); + }); +} + +module.exports = { + queryCalendarList, + queryEvents +}; \ No newline at end of file From df744ddb1fb7ee10b160e9526346ae09b954074c Mon Sep 17 00:00:00 2001 From: WLAN-Kabel Date: Sat, 11 Jan 2020 22:30:50 +0100 Subject: [PATCH 14/18] Added caldav tab --- admin/index_m.html | 79 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/admin/index_m.html b/admin/index_m.html index 0ba9e4c..40a70b2 100644 --- a/admin/index_m.html +++ b/admin/index_m.html @@ -19,6 +19,7 @@ @@ -100,6 +128,7 @@ @@ -128,7 +157,7 @@
- Activate Google calendar + Activate Google
@@ -154,6 +183,7 @@
+ @@ -164,6 +194,39 @@ +
+
+
+
+
+ + Activate CalDAV +
+
+
+ add +
+
account accessToken refreshTokenctag days color
+ + + + + + + + + + + + + + + + +
activenameidhostnameusernamepasswordctagpathlistIsLoadeddayscolor
+
+
+