Skip to content
  • Home
  • Recent
  • Tags
  • 0 Unread 0
  • Categories
  • Unreplied
  • Popular
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Visualisierung
  4. [Vorlage] MDCSS v2: ical Kalendar anzeigen

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    17
    1
    3.0k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    1.1k

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.4k

[Vorlage] MDCSS v2: ical Kalendar anzeigen

Scheduled Pinned Locked Moved Visualisierung
vismaterial uimaterial css
56 Posts 15 Posters 9.3k Views 20 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • UhulaU Uhula

    Update 2020.05.01

    • Anpassung an neues MduiBase (intern)
    • Anpassung an MDCSS 2.5
    • Serientermine vor dem aktuellem Datum werden nicht mehr angezeigt

    Update auf GitHub, siehe 1.Beitrag

    Um ein Feedback zu erhalten wäre es schön, wenn jeder, der diese Vorlagen nutzt, den 1.Beitrag des Themas positiv bewertet (Pfeil nach oben oder unten ;-) ). Ich kann dann auch abschätzen, ob sich die weitere Pflege lohnt. Thx!
    T Offline
    T Offline
    Tirador
    wrote on last edited by
    #32

    @Uhula super, dass mit den Serienterminen. Würde es dir etwas ausmachen, dass Skript etwas zubauen, so dass die Termine von x Tagen auch in einzelne Datenpunkte geschrieben werden. Das könnte man dann auch direkt im MessageHandler anzapfen. Ich würde das Skript erweitern und dir die Version senden.

    D UhulaU 2 Replies Last reply
    0
    • T Tirador

      @Uhula super, dass mit den Serienterminen. Würde es dir etwas ausmachen, dass Skript etwas zubauen, so dass die Termine von x Tagen auch in einzelne Datenpunkte geschrieben werden. Das könnte man dann auch direkt im MessageHandler anzapfen. Ich würde das Skript erweitern und dir die Version senden.

      D Offline
      D Offline
      der-eine
      wrote on last edited by
      #33

      @Tirador sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

      @Uhula super, dass mit den Serienterminen. Würde es dir etwas ausmachen, dass Skript etwas zubauen, so dass die Termine von x Tagen auch in einzelne Datenpunkte geschrieben werden. Das könnte man dann auch direkt im MessageHandler anzapfen. Ich würde das Skript erweitern und dir die Version senden.

      @Uhula das wäre super wenn Du das umsetzen könntest! :+1:

      1 Reply Last reply
      0
      • T Tirador

        @Uhula super, dass mit den Serienterminen. Würde es dir etwas ausmachen, dass Skript etwas zubauen, so dass die Termine von x Tagen auch in einzelne Datenpunkte geschrieben werden. Das könnte man dann auch direkt im MessageHandler anzapfen. Ich würde das Skript erweitern und dir die Version senden.

        UhulaU Offline
        UhulaU Offline
        Uhula
        wrote on last edited by
        #34

        @Tirador sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

        @Uhula super, dass mit den Serienterminen. Würde es dir etwas ausmachen, dass Skript etwas zubauen, so dass die Termine von x Tagen auch in einzelne Datenpunkte geschrieben werden. Das könnte man dann auch direkt im MessageHandler anzapfen. Ich würde das Skript erweitern und dir die Version senden.

        Das wäre im Script ja konfigurierbar "fireEvent4MessageHandler" oder so, stört mich nicht.
        Aber.
        Das wird nicht viel bringen. Das Script reagiert auf jede Änderung im iCal-JSON und baut die List/Table erneut auf. Es würde dann auch jedesmal wieder alle Termine in deinen MessageHandler feuern. Denn das Script merkt sich ja nicht, für welchen Termin es das schon gemacht hat ...

        Generell halte ich es auch für besser, wenn dein MessageHandler ohne ein weiteres Aufbereitungs-Script wie dieses hier funktioniert. Dann bist du unabhängiger und universeller. Insofern müsstest du lediglich einen MessageCreator schreiben, der iCal-JSON überwacht, die Serientermine zerpflückt, die Messages feuert und sich die auch merkt.

        Das Zerpflücken kannst du aus meinem Script übernehmen, ist lediglich eine for-Schleife.

        Oder habe ich "in einzelne Datenpunkte" nicht korrekt verstanden?

        Uhula - Leise und Weise
        Ex: ioBroker on Gigabyte NUC Proxmox

        T 1 Reply Last reply
        0
        • UhulaU Uhula

          @Tirador sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

          @Uhula super, dass mit den Serienterminen. Würde es dir etwas ausmachen, dass Skript etwas zubauen, so dass die Termine von x Tagen auch in einzelne Datenpunkte geschrieben werden. Das könnte man dann auch direkt im MessageHandler anzapfen. Ich würde das Skript erweitern und dir die Version senden.

          Das wäre im Script ja konfigurierbar "fireEvent4MessageHandler" oder so, stört mich nicht.
          Aber.
          Das wird nicht viel bringen. Das Script reagiert auf jede Änderung im iCal-JSON und baut die List/Table erneut auf. Es würde dann auch jedesmal wieder alle Termine in deinen MessageHandler feuern. Denn das Script merkt sich ja nicht, für welchen Termin es das schon gemacht hat ...

          Generell halte ich es auch für besser, wenn dein MessageHandler ohne ein weiteres Aufbereitungs-Script wie dieses hier funktioniert. Dann bist du unabhängiger und universeller. Insofern müsstest du lediglich einen MessageCreator schreiben, der iCal-JSON überwacht, die Serientermine zerpflückt, die Messages feuert und sich die auch merkt.

          Das Zerpflücken kannst du aus meinem Script übernehmen, ist lediglich eine for-Schleife.

          Oder habe ich "in einzelne Datenpunkte" nicht korrekt verstanden?

          T Offline
          T Offline
          Tirador
          wrote on last edited by
          #35

          @Uhula den ical zu zerpflücken würde bedeuten, dass ich den MessageStateCreator erheblich aufrüsten müsste, um weiterhin generisch zu arbeiten. Selbst wenn ich Optionen integriere um json zu verarbeiten fehlt noch viel kalenderlogik. Die Logik aus deinem Skript zu übernehmen führt zur Redundanz. Daher die Idee die Aufbereitung aus deinem Skript direkt in Datenpunkten fortzuschreiben.die mehrfache Auslösung ist grundsätzlich nicht problematisch. Hier würde ich noch eine Option im MessageStateCreator vorsehen, dass der Datenpunkt nur bei Änderungen des Werts neu getriggert wird.

          1 Reply Last reply
          0
          • G Offline
            G Offline
            G4l4h4d
            wrote on last edited by
            #36

            Ich habe das Script eingefügt und bekomme folgenden Fehler

            javascript.0	2020-05-09 22:09:19.604	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
            javascript.0	2020-05-09 22:09:19.604	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
            javascript.0	2020-05-09 22:09:19.603	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
            javascript.0	2020-05-09 22:09:19.602	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
            javascript.0	2020-05-09 22:09:19.601	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
            

            Es wird in den Objekten auch kein Eintag in Userdata angelegt?

            UhulaU 1 Reply Last reply
            0
            • G G4l4h4d

              Ich habe das Script eingefügt und bekomme folgenden Fehler

              javascript.0	2020-05-09 22:09:19.604	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
              javascript.0	2020-05-09 22:09:19.604	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
              javascript.0	2020-05-09 22:09:19.603	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
              javascript.0	2020-05-09 22:09:19.602	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
              javascript.0	2020-05-09 22:09:19.601	error	(973) Function "setObject" is not allowed. Use adapter settings to allow it.
              

              Es wird in den Objekten auch kein Eintag in Userdata angelegt?

              UhulaU Offline
              UhulaU Offline
              Uhula
              wrote on last edited by
              #37

              @G4l4h4d sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

              Es wird in den Objekten auch kein Eintag in Userdata angelegt?

              Du musst im Admin in den Eigenschaften der Javascript-Instanz Erlaube das Kommando setObject einschalten.

              010b0b2b-b443-4b35-95b5-6739ce7359dd-image.png

              Uhula - Leise und Weise
              Ex: ioBroker on Gigabyte NUC Proxmox

              G 1 Reply Last reply
              0
              • UhulaU Uhula

                @G4l4h4d sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                Es wird in den Objekten auch kein Eintag in Userdata angelegt?

                Du musst im Admin in den Eigenschaften der Javascript-Instanz Erlaube das Kommando setObject einschalten.

                010b0b2b-b443-4b35-95b5-6739ce7359dd-image.png

                G Offline
                G Offline
                G4l4h4d
                wrote on last edited by
                #38

                @Uhula Vielen Dank, wusste gar nicht das es aus ist :-)

                1 Reply Last reply
                0
                • ChaotC Offline
                  ChaotC Offline
                  Chaot
                  wrote on last edited by Chaot
                  #39

                  @Uhula
                  Ich bekomme beim zweiten Start die Fehlermeldung:

                  javascript.0	2020-06-12 21:39:26.740	warn	(460) at script.js.Kalender.MDUI-Ical:724:18
                  javascript.0	2020-06-12 21:39:26.740	warn	(460) at MduiShowIcal.start (script.js.Kalender.MDUI-Ical:112:26)
                  javascript.0	2020-06-12 21:39:26.739	warn	(460) at MduiShowIcal.doStart (script.js.Kalender.MDUI-Ical:366:14)
                  javascript.0	2020-06-12 21:39:26.739	warn	(460) at MduiShowIcal.onBuildHTML (script.js.Kalender.MDUI-Ical:608:73)
                  javascript.0	2020-06-12 21:39:26.739	warn	(460) at MduiShowIcal.getState (script.js.Kalender.MDUI-Ical:187:16)
                  javascript.0	2020-06-12 21:39:26.730	warn	(460) getState "0_userdata.0.mdui.showIcal.log0.filter" not found (3)
                  

                  Muss ich noch irgendwas einstellen das ich überlesen habe?

                  Edit:
                  Meldung ist jetzt plötzlich wieder weg.
                  Egal.
                  Danke für das Klasse Script!

                  ioBroker auf NUC unter Proxmox; VIS: 12" Touchscreen und 17" Touch; Lichtsteuerung, Thermometer und Sensoren: Tasmota (39); Ambiente Beleuchtung: WLED (9); Heizung: DECT Thermostate (9) an Fritz 6690; EMS-ESP; 1 Echo V2; 3 Echo DOT; 1 Echo Connect; 2 Echo Show 5; Unifi Ap-Ac Lite.

                  1 Reply Last reply
                  0
                  • Lars WalpurgisL Offline
                    Lars WalpurgisL Offline
                    Lars Walpurgis
                    wrote on last edited by Lars Walpurgis
                    #40

                    @Uhula Vielen Dank erstmal für das tolle Script es läuft wunderbar!
                    Ich habe zwei kurze Fragen und zwar:

                    1. Wie kann man anstatt des Datums vorn direkt anzeigen lassen, dass der Termin heute, in 1 Tage... ist? Der ical Adapter liefert das ja schon....!Datum.JPG

                    2. Ich nutze noch die MDCSS V1.8 und vermute, dass deswegen das Kuchen icon (cake im oberen Bild) nicht angezeigt wird, liegt das daran? Kann ich das einfach nach implementieren, oder muss ich die MDCSS Verion hochrüsten? Und wenn ja, habe ich eine Kompatibilität?

                    Danke für eure Antworten!

                    1 Reply Last reply
                    0
                    • Holger EtzelH Offline
                      Holger EtzelH Offline
                      Holger Etzel
                      wrote on last edited by Holger Etzel
                      #41

                      Hallo,

                      bekomme beim starten des Scripts folgende Meldung:

                      14:54:45.933 warn javascript.0 (22584) at MduiShowIcal.getState (script.js.Allgemein.Kalenderansicht:187:16)
                      14:54:45.934 warn javascript.0 (22584) at MduiShowIcal.onBuildHTML (script.js.Allgemein.Kalenderansicht:608:73)
                      14:54:45.934 warn javascript.0 (22584) at MduiShowIcal.doStart (script.js.Allgemein.Kalenderansicht:366:14)
                      14:54:45.935 warn javascript.0 (22584) at MduiShowIcal.start (script.js.Allgemein.Kalenderansicht:112:26)
                      14:54:45.936 warn javascript.0 (22584) at script.js.Allgemein.Kalenderansicht:724:18
                      14:54:46.027 info javascript.0 (22584) script.js.Allgemein.Kalenderansicht: [mduiShowIcal] script started
                      14:54:46.027 info javascript.0 (22584) script.js.Allgemein.Kalenderansicht: registered 3 subscriptions and 0 schedules

                      und im log:

                      javascript.0 2020-07-19 15:00:08.698 warn (22584) at process.topLevelDomainCallback (domain.js:126:23)
                      javascript.0 2020-07-19 15:00:08.697 warn (22584) at processImmediate (timers.js:658:5)
                      javascript.0 2020-07-19 15:00:08.696 warn (22584) at tryOnImmediate (timers.js:676:5)
                      javascript.0 2020-07-19 15:00:08.696 warn (22584) at runCallback (timers.js:705:18)
                      javascript.0 2020-07-19 15:00:08.695 warn (22584) at Immediate.setImmediate (/opt/iobroker/node_modules/iobroker.js-controller/lib/adapter.js:5384:37)
                      javascript.0 2020-07-19 15:00:08.695 warn (22584) at Object.stateChange (/opt/iobroker/node_modules/iobroker.javascript/main.js:451:25)
                      javascript.0 2020-07-19 15:00:08.694 warn (22584) at Object.callback (/opt/iobroker/node_modules/iobroker.javascript/lib/sandbox.js:1052:38)
                      javascript.0 2020-07-19 15:00:08.694 warn (22584) at Object.subscribe.obj (script.js.Allgemein.Kalenderansicht:364:60)
                      javascript.0 2020-07-19 15:00:08.694 warn (22584) at MduiShowIcal.onIcalTable (script.js.Allgemein.Kalenderansicht:391:12)
                      javascript.0 2020-07-19 15:00:08.693 warn (22584) at MduiShowIcal.onBuildHTML (script.js.Allgemein.Kalenderansicht:608:73)
                      javascript.0 2020-07-19 15:00:08.693 warn (22584) at MduiShowIcal.getState (script.js.Allgemein.Kalenderansicht:187:16)
                      javascript.0 2020-07-19 15:00:08.690 warn (22584) getState "0_userdata.0.mdui.showIcal.log0.filter" not found (3)

                      Habe ich noch was vergessen einzustellen?

                      Nach stundenlanger Wartezeit geht es auf einmal.

                      Gruß Holger

                      E 1 Reply Last reply
                      0
                      • Holger EtzelH Holger Etzel

                        Hallo,

                        bekomme beim starten des Scripts folgende Meldung:

                        14:54:45.933 warn javascript.0 (22584) at MduiShowIcal.getState (script.js.Allgemein.Kalenderansicht:187:16)
                        14:54:45.934 warn javascript.0 (22584) at MduiShowIcal.onBuildHTML (script.js.Allgemein.Kalenderansicht:608:73)
                        14:54:45.934 warn javascript.0 (22584) at MduiShowIcal.doStart (script.js.Allgemein.Kalenderansicht:366:14)
                        14:54:45.935 warn javascript.0 (22584) at MduiShowIcal.start (script.js.Allgemein.Kalenderansicht:112:26)
                        14:54:45.936 warn javascript.0 (22584) at script.js.Allgemein.Kalenderansicht:724:18
                        14:54:46.027 info javascript.0 (22584) script.js.Allgemein.Kalenderansicht: [mduiShowIcal] script started
                        14:54:46.027 info javascript.0 (22584) script.js.Allgemein.Kalenderansicht: registered 3 subscriptions and 0 schedules

                        und im log:

                        javascript.0 2020-07-19 15:00:08.698 warn (22584) at process.topLevelDomainCallback (domain.js:126:23)
                        javascript.0 2020-07-19 15:00:08.697 warn (22584) at processImmediate (timers.js:658:5)
                        javascript.0 2020-07-19 15:00:08.696 warn (22584) at tryOnImmediate (timers.js:676:5)
                        javascript.0 2020-07-19 15:00:08.696 warn (22584) at runCallback (timers.js:705:18)
                        javascript.0 2020-07-19 15:00:08.695 warn (22584) at Immediate.setImmediate (/opt/iobroker/node_modules/iobroker.js-controller/lib/adapter.js:5384:37)
                        javascript.0 2020-07-19 15:00:08.695 warn (22584) at Object.stateChange (/opt/iobroker/node_modules/iobroker.javascript/main.js:451:25)
                        javascript.0 2020-07-19 15:00:08.694 warn (22584) at Object.callback (/opt/iobroker/node_modules/iobroker.javascript/lib/sandbox.js:1052:38)
                        javascript.0 2020-07-19 15:00:08.694 warn (22584) at Object.subscribe.obj (script.js.Allgemein.Kalenderansicht:364:60)
                        javascript.0 2020-07-19 15:00:08.694 warn (22584) at MduiShowIcal.onIcalTable (script.js.Allgemein.Kalenderansicht:391:12)
                        javascript.0 2020-07-19 15:00:08.693 warn (22584) at MduiShowIcal.onBuildHTML (script.js.Allgemein.Kalenderansicht:608:73)
                        javascript.0 2020-07-19 15:00:08.693 warn (22584) at MduiShowIcal.getState (script.js.Allgemein.Kalenderansicht:187:16)
                        javascript.0 2020-07-19 15:00:08.690 warn (22584) getState "0_userdata.0.mdui.showIcal.log0.filter" not found (3)

                        Habe ich noch was vergessen einzustellen?

                        Nach stundenlanger Wartezeit geht es auf einmal.

                        Gruß Holger

                        E Offline
                        E Offline
                        Ente
                        wrote on last edited by
                        #42

                        @sigi234

                        Hallo siggi234,

                        danke für den Install-Screenshot. ;-)

                        sigi234S 1 Reply Last reply
                        0
                        • E Ente

                          @sigi234

                          Hallo siggi234,

                          danke für den Install-Screenshot. ;-)

                          sigi234S Online
                          sigi234S Online
                          sigi234
                          Forum Testing Most Active
                          wrote on last edited by sigi234
                          #43

                          @Ente sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                          @sigi234

                          Hallo siggi234,

                          danke für den Install-Screenshot. ;-)

                          Screenshot (674)_LI.jpg

                          /*
                          *** MduiShowIcal
                          Dieses Script überwacht den ical-Adapter und erzeugt bei Änderungen an dessen States HTML-List States für die Anzeige als 
                          Kalender in Listform mit
                          * Tagesauflösung von "von/bis"-Terminen, inkl. Berücksichtigung der Uhrzeiten
                          * Tagesdatum, Kalendarfarben aus ical oder optional aus dem Script
                          * Termintext und -ort
                          * optionalem Icon je Kalendar
                          * optionalem "ignore", wenn ein Kalendar unberücksichtigt bleiben soll
                          
                          Es werden States für n-Logs erzeugt, jedem, Log kann ein Standardfilter mitgegeben werden. In jedem Log-Ordner 
                          befindet sich ein list-HTML State, welcher direkt in der vis angezeigt werden kann (jeweils im basic-string (unescaped) Widget). 
                          Über optionale Filter als string (Bsp:':Abfall:') oder als RegExp (Bsp:'/Feiertag|Geburtstag/') kann festgelegt werden, 
                          welche Einträge beim Aufbau der list-HTML States berücksichtigt werden. 
                          Bsp.: 
                          log0 Filter: "abfall" oder ":Abfall:" (=Kalendarname) -> Zeigt nur Abfalltermine
                          log0 Filter: "ferien" oder ":Ferien:" (=Kalendarname) -> Zeigt nur Ferientermine
                          
                          
                          **** Installation
                          Einfach als serverseitiges Script installieren und starten-5 Sek warten-stoppen-starten. Beim 1.Start werden 
                          die notwendigen States unter STATE_PATH = '0_userdata.0.mdui.showIcal.' erzeugt. Erst beim 2.Start
                          instanziiert das Script die Event-Handler und läuft dann.
                          
                          **** Konfiguration
                          Eigentlich ist keine notwendig.
                          Optional in der Funktion MduiShowIcal|doInit() eine Anpassung der KONFIGURATION vornehmen
                          Optional Anpassung der tmpList.
                            
                          **** Dokumentation
                          https://github.com/Uhula/ioBroker-Material-Design-Style/wiki/3.5-MduiShowIcal
                          
                          ###### Um ein Feedback zu erhalten wäre es schön, wenn jeder, der diese Vorlagen nutzt, den  1.Beitrag des Themas positiv bewertet (Pfeil nach oben oder unten ;-) ). Ich kann dann auch abschätzen, ob sich die weitere Pflege lohnt. Thx!
                          
                          ***** States
                          Unter dem STATE_PATH werden die folgenden States erzeugt:
                          version : Script-Version, wird verwendet um Script-Updates zu erkennen
                          updatePressed : auf true setzen, wenn ein table/list update außerhalb des Intervals erfolgen soll
                          
                          Weiterhin werden MAX_LOG_FOLDER Unterordner im STATE_PATH erzeugt (N=0-9):
                          
                          * LogN.table        : enthält die table-HTML für ein basic-string (unescaped) Widget
                          * LogN.list         : enthält die list-HTML für ein basic-string (unescaped) Widget
                          * LogN.count        : Anzahl der Log-Zeilen (wenn das Log mit '/:error:|:warn:/' gefiltert ist, dann ist es die Anzahl der Fehler/Warnungen)
                          * LogN.filter       : Filter, der auch die logCache angewendet wurde im .table/.list zu erzeugen (siehe Filter)
                          * LogN.lastUpdate   : Timestamp des letzten Updates
                          
                          
                          ***** Filter
                          In den filter-States können sowohl strings (Bsp:'error') als auch RegExp-Strings (Bsp:'/warn|error/') 
                          hinterlegt werden. RegExp-Strings werden an den einschließenden  '/' erkannt. Über den ':' kann der Anfang
                          eines Feldes mit in den Filter einbezogen werden. 
                          Beispiele: 
                          '/Feiertag|Geburtstag/' (RegExp) zeigt alle Zeilen an, in denen 'Feiertag' oder 'Geburtstag' in irgendeinem Feld vorkommen
                          ':Abfall:' (string) zeigt alle Zeilen an, welche derKalendar 'Abfall' lautet
                          'Arzt' (string) zeigt alle Zeilen an, in denen 'Arzt' in irgendeinem Feld vorkommt
                          
                          **** Lizenz
                          (c) 2020 by UH, MIT License, no warranty, use on your own risc
                          
                          *** Changelog
                          2020.05.01 UH 
                          * Anpassung an neues MduiBase (intern)
                          * Anpassung an MDCSS 2.5
                          * Serientermine vor dem aktuellem Datum werden nicht mehr angezeigt
                          
                          */
                          
                          // ------------------------------------------------------------------------------------- 
                          // MduiBase
                          // ------------------------------------------------------------------------------------- 
                          
                          class MduiBase {
                          
                              constructor() {
                                this.init();
                              }
                              
                              //
                              init() {
                                  // const
                                  this.DEBUG      = false;
                                  this.VERSION    = '1.0/2020-01-01';
                                  this.NAME       = 'mduiBase';
                                  this.STATE_PATH = '0_userdata.0.mdui.base.';
                                  this.STATE_UNKNOWN    =  0;
                                  this.STATE_INSTALLING = 10;
                                  this.STATE_INSTALLED  = 11;
                                  this.STATE_STARTING   = 20;
                                  this.STATE_STARTED    = 21;
                                  this.STATE_STOPPING   = 30;
                                  this.STATE_STOPPED    = 31;
                              
                                  // var
                                  this.state = this.STATE_UNKNOWN;
                                  this.states = [];
                                  this.subscribers = [];
                                  this.schedulers = [];
                              
                                  this.doInit();
                              
                                  // init der states
                                  this.states.push( { id:'version',     common:{name:'installed script-version', write:false, def:this.VERSION} } );
                              }
                              
                              //
                              // start the script/class
                              //
                              start() {
                                  // beim 1.Start nur die States erzeugen
                                  if ( !this.existState("version") || (this.getState('version').val!=this.VERSION) ) {
                                      for (let s=0; s<this.states.length; s++) { this.createState( this.states[s].id ); }
                                      this.logWarn('first script start, creating states for version '+this.VERSION+', automatic restarting script again in 10 sec ...');
                                      setStateDelayed(this.STATE_PATH + 'version', this.VERSION, 3000);
                                      setTimeout( this.start.bind(this), 10000 );
                                      this.state = this.STATE_INSTALLED; 
                                      return;
                                  }
                                  switch (this.state) {
                                      case this.STATE_UNKNOWN : ;
                                      case this.STATE_INSTALLING : ;
                                      case this.STATE_INSTALLED : ;
                                      case this.STATE_STOPPED : {
                                          this.state = this.STATE_STARTING; 
                                          if (this.doStart()) {
                                              this.log('script started');
                                              this.state = this.STATE_STARTED;
                                          }
                                          break;    
                                      }
                                      case this.STATE_STARTING : ;
                                      case this.STATE_STARTED : {
                                          this.logWarn('script already starting/started');
                                          break;    
                                      }
                                      case this.STATE_STOPPING : {
                                          this.logWarn('script is stopping, pls start later again');
                                          break;    
                                      }
                                
                                  } 
                              }
                              
                              //
                              // stop the script/class
                              //
                              stop() {
                                  switch (this.state) {
                                      case this.STATE_STARTED : {
                                          this.state = this.STATE_STOPPING; 
                                          if (this.doStop()) {
                                              for (let i=0; i<this.subscribers.length; i++) if (this.subscribers[i] !== undefined) unsubscribe( this.subscribers[i] );
                                              this.subscribers = [];
                                              for (let i=0; i<this.schedulers.length; i++) if (this.schedulers[i] !== undefined) clearSchedule( this.schedulers[i] );
                                              this.schedulers = [];
                                              this.state = this.STATE_STOPPED; 
                                              this.log('script stopped');
                                          }
                                          break;    
                                      }
                                      default : {
                                          this.log('cant stopp script, because not startet');
                                      }
                                  } 
                              }
                              
                              //
                              // virtual functions, overwrite it 
                              //
                              doInit() { return true; }
                              doStart() { return true; }
                              doStop() { return true; }
                              
                              // einen on-Handler registrieren
                              subscribe( handler ) {
                                  this.subscribers.push( handler );
                              }
                              
                              // einen timer registrieren
                              schedule( handler ) {
                                  this.schedulers.push( handler );
                              }
                              
                              //
                              // tool functions 
                              //
                              logDebug(msg) { if (this.DEBUG) console.log('['+this.NAME+'] '+msg); }
                              log(msg) { console.log('['+this.NAME+'] '+msg); }
                              logWarn(msg) { console.warn('['+this.NAME+'] '+msg); }
                              logError(msg) { console.error('['+this.NAME+'] '+msg); }
                              
                              // über den $-Operator nachsehen, ob der state bereits vorhanden ist
                              // getState().notExists geht auch, erzeugt aber Warnmeldungen!
                              existState(id) {
                                  return ( $(this.STATE_PATH+id).length==0?false:true);
                              }
                              
                              // wrapper, adds statepath to state-ID
                              getState(id) {
                                  return getState(this.STATE_PATH + id);
                              }
                              
                              // like setState(), but adds statepath to state_ID and checks if state exists, when not, creates it
                              setState(id,value) {
                                  if ( !this.existState(id) ) this.createState(id,value,undefined);
                                  else setState( this.STATE_PATH + id, value);
                              }
                              
                              // like cresteState(), but adds statepath to state_ID and checks if state exists, when not, creates it
                              createState(id,value,common) {
                                  if ( !this.existState(id) ) {
                                      if (common===undefined) {
                                          // id im states-Array suchen
                                          for (var i=0; i<this.states.length; i++) { 
                                              if (this.states[i].id==id) {
                                                  if (this.states[i].hasOwnProperty('common'))
                                                      common = this.states[i].common;
                                                 break;
                                              }   
                                          }
                                      }
                                      if ( (typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
                                      // unter "0_userdata.0"
                                      let obj = {};
                                      obj.type = 'state';
                                      obj.native = {};
                                      obj.common = common;
                                      setObject(this.STATE_PATH + id, obj, (err) => {
                                              if (err) {
                                                  this.log('cant write object for state "' + this.STATE_PATH + id + '": ' + err);
                                              } else { 
                                                  this.log('state "' + this.STATE_PATH + id + '" created');
                                              }
                                      });
                              
                                      setTimeout( setState, 3000, this.STATE_PATH + id, value );
                                  }
                              }
                              
                              // true, if str contains filter string or regexp 
                              fitsFilter(str, filter) {
                                  if ( (filter===undefined) || !filter || (filter=='') )
                                      return true;
                                  if ( filter instanceof RegExp )  {
                                      if (str.match( filter ) != null) return true;
                                  } else if (typeof filter == 'string') {
                                      if(str.includes(filter)) return true;
                                  }
                                  return false;        
                              }
                              
                              //
                              escapeRegExp(str) {
                                  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 
                              }
                              
                              // wandelt eine Farbe im hex-Format (#000000) in ein RGB-Array[2] um
                              hexToRGB(hex) {
                                  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
                                  return result 
                                      ? [parseInt(result[1],16),parseInt(result[2],16),parseInt(result[3],16)]
                                      : [0,0,0];
                              };
                              
                              // Helligkeit berechnen
                              getLuminance(r, g, b) {
                                  var a = [r, g, b].map(function (v) {
                                      v /= 255;
                                      return v <= 0.03928
                                          ? v / 12.92
                                          : Math.pow( (v + 0.055) / 1.055, 2.4 );
                                  });
                                  return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
                              }
                              
                              // Kontrats berechnen
                              getContrast(rgb1, rgb2) {
                                  var l1 = this.getLuminance(rgb1[0], rgb1[1], rgb1[2]) + 0.05;
                                  var l2 = this.getLuminance(rgb2[0], rgb2[1], rgb2[2]) + 0.05;
                                  if ( l1 > l2 ) return l1 / l2 
                                  else return l2 / l1;
                              }
                              
                              // liefert die fontColor auf Basis der backgroundColor durch Berechnung
                              // des Kontrasts
                              getFontColor(backgroundColor) {
                                  if ( this.getContrast(this.hexToRGB(backgroundColor),this.hexToRGB("#000000")) < 6 ) 
                                      return "#ffffff";
                                  else
                                      return "#000000";
                              }
                              
                              }
                              
                              // ------------------------------------------------------------------------------------- 
                              // MduiLogHMDevices
                              // ------------------------------------------------------------------------------------- 
                              
                              class MduiShowIcal extends MduiBase {
                              
                              constructor() {
                                  super();
                              }
                              
                              doInit() {
                                super.doInit();
                              
                                // const
                                this.DEBUG = false;
                                this.VERSION = '1.0/2020-03-22';
                                this.NAME = 'mduiShowIcal';
                                this.DAY_MILLISECONDS = 60 * 60 * 24 * 1000;
                              
                                // -----------------------  
                                // optional: KONFIGURATION
                                // -----------------------  
                                                     // state-Pfad unter dem die States angelegt werden  
                                this.STATE_PATH      = '0_userdata.0.mdui.showIcal.'; 
                                                     // Anzahl der Table/List Ordner mit eigenem Filter/View
                                this.MAX_LOG_FOLDER  = 3;   
                                                     // max.Anzahl der Zeilen für die Table/List Ausgabe
                                this.MAX_TABLE_ROWS  = 200; 
                                                     // Objekt-Pfad zum ical.x.data.table
                                this.ICAL_TABLE      = 'ical.0.data.table';
                                                     // siehe: https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#formatdate
                                this.DATE_FORMAT     = 'W DD.MM.YYYY hh:mm';
                                                     // optional können dem Kalendar noch Icons und abweichende
                                                     // Farben angegeben werden (diese überschreiben jene aus iCal)
                                                     // 'icon'     : 'Icon-Name' (MDCSS/Google WebFont)
                                                     // 'calColor' : *#rrggbb' abweichende Kalendarfarbe 
                                                     // 'ignore'   : true|false Kalendar komplett ignorieren
                                this.CALENDAR        = {'mdui-Abfall'      : {'icon':'delete_outline', 'calcolor':'orange' },
                                                        'mdui-Geburtstage' : {'icon':'cake'},
                                                        'Familie'          : {'ignore':true}
                                                         
                                                       };
                              
                                // -----------------------  
                                // ENDE KONFIGURATION
                                // -----------------------  
                              
                                // var
                                this.logs = [];
                                for (let i=0; i<=this.MAX_LOG_FOLDER && i<10; i++) 
                                    this.logs.push({filter:'' });
                                
                              
                                // init der states
                                this.states.push( { id:'version',     common:{name:'installed script-version', write:false, def:this.VERSION} } );
                                this.states.push( { id:'updatePressed',common:{name:'update button pressed', write:true, type:'boolean', def:'false', role:'button' }} );
                                
                                let defFilter;
                                for (let i=0; i<=this.MAX_LOG_FOLDER && i<10; i++) {
                                    switch (i) {
                                        case 1 : defFilter = ':Abfall:'; break;   
                                        case 2 : defFilter = 'Geburtstag'; break;   
                                        case 3 : defFilter = ''; break;   
                                        default: defFilter = undefined;
                                    }
                                    this.states.push( { id:'log'+i+'.table',      common:{name:'ioBroker-log as table', write:false, role:'html' }} );
                                    this.states.push( { id:'log'+i+'.list',       common:{name:'ioBroker-log as list', write:false, role:'html' }} );
                                    this.states.push( { id:'log'+i+'.count',      common:{name:'ioBroker-log count', write:false, type:'number', def:'0' }} );
                                    this.states.push( { id:'log'+i+'.filter',     common:{name:'ioBroker-log filter', write:true, def:defFilter}} );
                                    this.states.push( { id:'log'+i+'.lastUpdate', common:{name:'ioBroker-log last update', write:false, def:'0' }} );
                                }
                              
                                return true;  
                              }
                              
                              // start the script/class
                              doStart() {
                                  super.doStart();
                                  
                                  // subscriber erzeugen
                                  this.subscribe( on( this.STATE_PATH+'updatePressed', obj => { this.onUpdate(obj) } ));
                                  this.subscribe( on( new RegExp( this.STATE_PATH+'*.filter' ), obj => { this.onFilter(obj) } ));
                                  this.subscribe( on( this.ICAL_TABLE, obj => { this.onIcalTable(obj) } ));
                              
                                  this.onBuildHTML();
                                  return true;
                              }
                              
                              // stop the script/class
                              doStop() {
                                  super.doStop();
                                  return true;
                              }
                              
                              // 
                              onUpdate(obj) {
                                  if (obj.state.val===true) {
                                      this.onBuildHTML();
                                  }
                                  this.setState('updatePressed', false);
                              }
                              
                              // filter, sort events
                              onFilter(obj) {
                                this.onBuildHTML();
                              }
                              
                              // Ical table hat sich geändert
                              onIcalTable(obj) {
                                this.onBuildHTML();
                              }
                              
                              
                              
                              // creates the HTML states for every log
                              /*
                              'date' => "→ 16.10.2017" 
                              'event' => "9.30 - 16.30 Uhr Stopka " 
                              '_class' => "ical_Kerstin ical_today" 
                              '_date' => "2017-10-16T07:30:00.000Z" 
                              '_end' => "2017-10-16T14:30:00.000Z" 
                              '_section' => "" 
                              '_IDID' => "040000008200E00074C5B7101A82E008000000007645DC55A6DFC44FB2EC6FEA9EFEA33C100000007688316058136F42AD128D91103543C9" 
                              '_allDay' => "false" 
                              '_rule' => " " 
                              '_calName' => "Kerstin" 
                              
                              Optionen der ical-Instanz:
                                  'daysPreview' => "7"
                                  'colorize' => "false"
                                  'defColor' => "white"
                                  'fulltime' => " 00:00"
                                  'dataPaddingWithZeros' => "true"
                                  'replaceDates' => "false"
                                  'language' => "de"
                                  'everyCalOneColor' => "true"
                                  'calendars' (array) 
                                      '0' (array) 
                                          'name' => "Abfall"
                                          'url' => "https://calendar.google.com/calendar/ical/ruo0ddgalu03qq2ehpm8imqnk4%40group.calendar.google.com/private-a30aac0367f8b50cfd7373f6222d29b4/basic.ics"
                                          'user' => ""
                                          'pass' => ""
                                          'sslignore' => ""
                                          'color' => ""
                              */
                              
                              isSameDay(d1,d2) {
                                  return (d1.getDate()==d2.getDate()) && (d1.getMonth()==d2.getMonth()) && (d1.getFullYear()==d2.getFullYear());
                              }
                              
                              getWeekNumber( date ) {
                                  let d = new Date(date);
                                  d.setHours(0,0,0);
                                  d.setDate(d.getDate()+4-(d.getDay()||7));
                                  return Math.ceil((((d-new Date(d.getFullYear(),0,1))/8.64e7)+1)/7);
                              };            
                              
                              //
                              buildEntry( entry ) {
                                  const WEEKDAY_NAMES = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"];
                                  const MONTH_NAMES = ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"];
                              
                                  let beginDate = new Date( entry.beginDateISO );
                                  entry.beginTime = beginDate.getTime();
                                  entry.beginWeekDay = beginDate.getDay(); // 0=Sonntag 6=Samstag
                                  entry.beginWeekDayName = WEEKDAY_NAMES[entry.beginWeekDay]; 
                                  entry.beginDay = beginDate.getDate();
                                  entry.beginMonth = beginDate.getMonth();
                                  entry.beginMonthName = MONTH_NAMES[entry.beginMonth]; 
                                  entry.beginYear = beginDate.getFullYear();
                                  entry.beginHour = beginDate.getHours();
                                  entry.beginMinute = beginDate.getMinutes();
                                  entry.beginDate = formatDate(beginDate,  this.DATE_FORMAT);
                              
                                  let currDate = new Date( entry.currDateISO );
                                  entry.currTime = currDate.getTime();
                                  entry.currWeekDay = currDate.getDay(); // 0=Sonntag 6=Samstag
                                  entry.currWeekDayName = WEEKDAY_NAMES[entry.currWeekDay]; 
                                  entry.currDay = currDate.getDate();
                                  entry.currMonth = currDate.getMonth();
                                  entry.currMonthName = MONTH_NAMES[entry.currMonth]; 
                                  entry.currYear = currDate.getFullYear();
                                  entry.currHour = currDate.getHours();
                                  entry.currMinute = currDate.getMinutes();
                                  entry.currDate = formatDate(currDate,  this.DATE_FORMAT);
                                  entry.currDateOnly = entry.currYear*10000+entry.currMonth*100+entry.currDay;
                              
                              
                                  let endDate = new Date( entry.endDateISO );
                                  //allDay Korrektur: liefert immer einen Tag zu viel
                                  if (entry.allDay && endDate.getHours()==0) endDate.setTime( endDate.getTime() - this.DAY_MILLISECONDS);
                                  entry.endTime = endDate.getTime();
                                  entry.endWeekDay = endDate.getDay(); // 0=Sonntag 6=Samstag
                                  entry.endDay = endDate.getDate();
                                  entry.endMonth = endDate.getMonth();
                                  entry.endYear = endDate.getFullYear();
                                  entry.endHour = endDate.getHours();
                                  entry.endMinute = endDate.getMinutes();
                                  entry.endDate = formatDate(endDate, this.DATE_FORMAT);
                              
                                  // 
                                  if (entry.currWeekDay==0 || entry.currWeekDay==6) entry.dayColor = '#f44336'
                                  else entry.dayColor = 'inherited';
                              
                                  // 
                                  if (entry.currWeekDay==1) entry.week = this.getWeekNumber(currDate)+'.W';
                                  else entry.week = '';
                              
                                  // 
                                  if (entry.currTime < Date.now() ) entry.opacity = '.66'
                                  else entry.opacity = '1';
                              
                                  // Zeitraumangabe berechnen
                                  entry.hint = '';
                                  if ( !this.isSameDay(beginDate, endDate) ) {
                                          // mehrtägig
                                          if (entry.allDay)
                                              entry.timeSpan = 'ganztägig ';
                                          else if ( this.isSameDay(beginDate, currDate) ) 
                                                  entry.timeSpan = 'ab ' + formatDate(beginDate,'hh:mm');
                                               else if ( this.isSameDay(endDate, currDate) ) 
                                                        entry.timeSpan = 'bis ' + formatDate(endDate,'hh:mm');
                                                    else 
                                                         entry.timeSpan = 'ganztägig ';
                                      } else {
                                          // an einem Tag
                                          if (entry.allDay)
                                              entry.timeSpan = 'ganztägig';
                                          else if ( (entry.beginHour!=entry.endHour) || (entry.beginMinute!=entry.endMinute)  ) 
                                                   entry.timeSpan = formatDate(beginDate,'hh:mm') + '-' + formatDate(endDate,'hh:mm');
                                               else   
                                                   entry.timeSpan = formatDate(beginDate,'hh:mm');
                                      }
                                  return entry;        
                              };
                              
                              
                              onBuildHTML() { try {
                              
                                  let json = [];  
                                  let calTable = getState(this.ICAL_TABLE);
                                  let inst     = getObject("system.adapter."+this.ICAL_TABLE.substr(0,6));
                                  let instopt  = inst.native;
                                  let calendar = {};
                                  let cal      = {};
                                  let calOptions = {};
                                  let todayDate = new Date();
                                  let today = todayDate.getFullYear()*10000+todayDate.getMonth()*100+todayDate.getDate();
                              
                              
                                  for (var i = 0; i < calTable.val.length; i++) { 
                                    cal = calTable.val[i];
                                    let entry = {};
                                    if ( cal._calName != calendar.name ) {
                                          calendar = {};
                                          // color suchen
                                          for (let c = 0; c < instopt.calendars.length; c++ ) {
                                              if (cal._calName == instopt.calendars[c].name ) {
                                                  calendar = instopt.calendars[c];
                                                  break;
                                              }
                                          }
                                          // options suchen
                                          if (this.CALENDAR.hasOwnProperty(cal._calName)) calOptions = this.CALENDAR[cal._calName];
                                          else calOptions={};
                                      }    
                                      if (calOptions.hasOwnProperty('ignore') && calOptions.ignore ) continue;
                              
                                      if (calOptions.hasOwnProperty('calcolor')) entry.calColor = calOptions.calcolor;
                                      else if (calendar.color !== "") entry.calColor = calendar.color;
                                           else entry.calColor = '#000000';
                                      entry.color = this.getFontColor( entry.calColor ); 
                                      if (calOptions.hasOwnProperty('icon')) entry.icon = calOptions.icon;
                                      else entry.icon='';
                              
                                      entry.date = cal.date;
                                      entry.event = cal.event;
                                      entry.calName = cal._calName;
                                      entry.beginDateISO = cal._date;
                                      entry.currDateISO = cal._date;
                                      entry.endDateISO  = cal._end;
                                      entry.allDay  = cal._allDay; 
                                      entry.location = cal.location;
                              
                                      entry = this.buildEntry( entry);
                              
                                      if (entry.currDateOnly >= today)
                                          json.push( entry );
                              
                                      // Listenansicht
                                      // in calTable steht nur ein Eintrag für jeden Beginn, für die List-Darstellung
                                      // sind diese auch je Tag notwendig - hier jetzt bilden 
                                      if ( (entry.beginDay!=entry.endDay) || (entry.beginMonth!=entry.endMonth) || (entry.beginYear!=entry.endYear) ) {
                                          let currTime = new Date(entry.beginDateISO).getTime() + this.DAY_MILLISECONDS;
                                          let endTime = new Date(entry.endDateISO).getTime();
                                          if (entry.allDay) endTime -= + this.DAY_MILLISECONDS;
                                          let dayMax=Math.trunc( 2 + (endTime - currTime) /this. DAY_MILLISECONDS); 
                                          entry.hint += ' (Tag 1/'+dayMax+')';
                                          let dayCount=2; 
                                          while (currTime <= endTime && dayCount<100) {
                                              let newEntry = {};
                                              Object.assign(newEntry, entry);
                                              newEntry.currDateISO = new Date(currTime).toISOString();
                                              newEntry = this.buildEntry( newEntry );
                                              newEntry.hint += ' (Tag '+dayCount+'/'+dayMax+')';
                                              if (newEntry.currDateOnly >= today)
                                                  json.push( newEntry );
                                              currTime = currTime + this.DAY_MILLISECONDS;
                                              dayCount++;
                                          }
                              
                                      }
                                  }
                              
                                  // sortieren
                                  json.sort( (l,r) => {
                                            let lv=l['currTime'],rv=r['currTime'];
                                            return ((lv < rv) ? -1 : (lv > rv) ? 1 : 0);
                                        } );
                                      
                                // build table/list HTML
                                for (let i=0; i<=this.MAX_LOG_FOLDER && i<10; i++) {
                                    let log = this.logs[i];
                                    log.filter = '';
                                    log.ts = 0;
                                    log.idState = 'log'+i;
                                    if (this.existState(log.idState+'.filter')) log.filter = this.getState(log.idState+'.filter').val;
                                    if (this.existState(log.idState+'.lastClear')) log.ts = this.getState(log.idState+'.lastClear').val;
                              
                                    this.convertJSON2HTML(json, log);
                                }
                              } catch(err) { this.logError( 'onBuildHTML: '+err.message ); }  }
                              
                              
                              // color date event calName beginDate endDate allDay
                              convertJSON2HTML(json, log) {
                              const tmpTable = {
                              header : 
                              `<tr>
                              <th style="text-align:right;"></th>
                              <th style="text-align:left;"></th>
                              <th style="text-align:left;"></th>
                              <th style="text-align:left;"></th>
                              <th style="text-align:left;"></th>
                              <th style="text-align:left; min-width:12em;">Betreff</th>
                              <th style="text-align:left;">Zeit</th>
                              <th style="text-align:left;">Ort</th>
                              <th style="text-align:left;">Kalendar</th>
                              <th style="text-align:left;"></th>
                              </tr>`,
                              row : 
                              `<tr>
                              <td style="text-align:right;">
                                 <span style="display:{showDay}; color:{dayColor}; font-size:1.5em; opacity:1; font-weight:bold;">{currDay}</span>
                              </td>
                              <td>
                                 <span style="display:{showDay}; font-size:0.8em; margin-top:0.3em; margin-left:4px; opacity:.8;">{currMonthName}</span>
                              </td>
                              <td>
                                 <span style="display:{showDay}; font-size:0.8em; margin-top:0.3em; opacity:.8;">{currWeekDayName}</span>
                              </td>
                              <td>
                                <span style="display:inline-block; width:.8em; height:.8em; margin-top:0.3em; background:{calColor}; border-radius:50%;">&nbsp;</span>
                              </td>
                              <td>
                                <i class='material-icons mdui-center {color}' style='font-size:1.2em;'>{icon}</i>
                              </td>
                              <td>{event}</td>
                              <td><span style="font-size:1.0em; opacity:.8;">{timeSpan} {hint}</span></td>
                              <td>{location}</td>
                              <td><span style="font-size:0.8em; opacity:.8;color:{calColor};">{calName}</span></td>
                              <td></td>
                              </tr>`
                              }
                              
                              const tmpList = {
                              row : 
                              `<div class="mdui-listitem" style="font-size:1em; width:100%; display:flex; opacity:{opacity};">
                                <div style="min-width:3.5em;">
                                  <div style="display:{showDay}; color:{dayColor};">
                                    <span style="font-size:1.5em; opacity:1; font-weight:bold;">{currDay}</span>
                                    <span style="font-size:0.8em; margin:4px; opacity:.8;">{currMonthName}<br/>
                                    {currWeekDayName}</span>
                                  </div>
                                  <div style="display:{showDay}; text-align:right; font-size:0.6em; opacity:.6;">{week}</div>
                                </div>
                                <div style="min-width:1.2em;">
                                  <div style="width:.8em; height:.8em;  margin:.1em; text-align:center; background:{calColor}; border-radius:50%;">&nbsp;</div>
                                  <div class="mdui-icon" style="font-size:1.1em; text-align:center; margin-top:0.33em;">{icon}</div>
                                </div>
                                <div style="width:100%; margin-left:.25em;">
                                  <div style="">
                                    <div style="font-size:1.1em;">{event}</div>
                                  </div>
                                  <div style="width:100%; display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between;">
                                    <div style="font-size:1.0em; opacity:.8;">
                                      {timeSpan}
                                      <span style="font-size:0.8em;">{hint} {location}</span>
                                    </div>
                                    <div style="font-size:0.8em; opacity:.8;color:{calColor};">{calName}</div>
                                  </div>
                                </div>
                              </div>`}
                                  // build htmlTable and htmlList
                                  let htmlTable  = "<table><thead>"+tmpTable.header+"</thead><tbody>";
                                  for (let [key, value] of Object.entries(log)) htmlTable = htmlTable.replace(new RegExp('{'+key+'}','g'),value);
                                 
                                  let htmlList  = "";
                                  let entry, tr;
                                  let count = 0;
                                  // filter as regex?
                                  if ( log.filter!==undefined && typeof log.filter == 'string' && log.filter.startsWith('/') && log.filter.endsWith('/') && (log.filter.length>=2) )  {
                                      log.filter = new RegExp(log.filter.substr(1,log.filter.length-2), 'i');
                                  }
                              
                                  let lastEntry = {};
                                  for (var i = 0; i < json.length && count<this.MAX_TABLE_ROWS; i++) { 
                                      entry = json[i];
                                      if (this.fitsFilter(':' + entry.currDate + ':' + entry.event +':'+entry.calName + ':' + entry.location + ':',log.filter)) {
                                          entry.showDay = (lastEntry=={}) || (entry.currDay!=lastEntry.currDay) || (entry.currMonth!=lastEntry.currMonth) || (entry.currYear!=lastEntry.currYear)?'flex':'none';
                                          lastEntry = entry;
                                          tr = tmpTable.row;    
                                          for (let [key, value] of Object.entries(entry)) tr = tr.replace(new RegExp('{'+key+'}','g'),value);
                                          htmlTable+=tr;
                                          tr = tmpList.row;    
                                          for (let [key, value] of Object.entries(entry)) tr = tr.replace(new RegExp('{'+key+'}','g'),value);
                                          htmlList+=tr;
                                          count++;
                                      }
                                  }
                                  htmlTable+="</body></table>";    
                                  this.setState(log.idState+'.table', htmlTable);  
                                  this.setState(log.idState+'.list', htmlList);  
                                  this.setState(log.idState+'.count', count);  
                                  this.setState(log.idState+'.lastUpdate', +new Date());  
                              }
                              
                              }
                              
                              
                              // create instance and start
                              var mduiShowIcal = new MduiShowIcal( );
                              mduiShowIcal.start();
                              
                              // on script stop, stop instance too
                              onStop(function () { 
                                  mduiShowIcal.stop(); 
                              }, 1000 );
                          

                          Bitte benutzt das Voting rechts unten im Beitrag wenn er euch geholfen hat.
                          Immer Daten sichern!

                          E 1 Reply Last reply
                          0
                          • sigi234S sigi234

                            @Ente sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                            @sigi234

                            Hallo siggi234,

                            danke für den Install-Screenshot. ;-)

                            Screenshot (674)_LI.jpg

                            /*
                            *** MduiShowIcal
                            Dieses Script überwacht den ical-Adapter und erzeugt bei Änderungen an dessen States HTML-List States für die Anzeige als 
                            Kalender in Listform mit
                            * Tagesauflösung von "von/bis"-Terminen, inkl. Berücksichtigung der Uhrzeiten
                            * Tagesdatum, Kalendarfarben aus ical oder optional aus dem Script
                            * Termintext und -ort
                            * optionalem Icon je Kalendar
                            * optionalem "ignore", wenn ein Kalendar unberücksichtigt bleiben soll
                            
                            Es werden States für n-Logs erzeugt, jedem, Log kann ein Standardfilter mitgegeben werden. In jedem Log-Ordner 
                            befindet sich ein list-HTML State, welcher direkt in der vis angezeigt werden kann (jeweils im basic-string (unescaped) Widget). 
                            Über optionale Filter als string (Bsp:':Abfall:') oder als RegExp (Bsp:'/Feiertag|Geburtstag/') kann festgelegt werden, 
                            welche Einträge beim Aufbau der list-HTML States berücksichtigt werden. 
                            Bsp.: 
                            log0 Filter: "abfall" oder ":Abfall:" (=Kalendarname) -> Zeigt nur Abfalltermine
                            log0 Filter: "ferien" oder ":Ferien:" (=Kalendarname) -> Zeigt nur Ferientermine
                            
                            
                            **** Installation
                            Einfach als serverseitiges Script installieren und starten-5 Sek warten-stoppen-starten. Beim 1.Start werden 
                            die notwendigen States unter STATE_PATH = '0_userdata.0.mdui.showIcal.' erzeugt. Erst beim 2.Start
                            instanziiert das Script die Event-Handler und läuft dann.
                            
                            **** Konfiguration
                            Eigentlich ist keine notwendig.
                            Optional in der Funktion MduiShowIcal|doInit() eine Anpassung der KONFIGURATION vornehmen
                            Optional Anpassung der tmpList.
                              
                            **** Dokumentation
                            https://github.com/Uhula/ioBroker-Material-Design-Style/wiki/3.5-MduiShowIcal
                            
                            ###### Um ein Feedback zu erhalten wäre es schön, wenn jeder, der diese Vorlagen nutzt, den  1.Beitrag des Themas positiv bewertet (Pfeil nach oben oder unten ;-) ). Ich kann dann auch abschätzen, ob sich die weitere Pflege lohnt. Thx!
                            
                            ***** States
                            Unter dem STATE_PATH werden die folgenden States erzeugt:
                            version : Script-Version, wird verwendet um Script-Updates zu erkennen
                            updatePressed : auf true setzen, wenn ein table/list update außerhalb des Intervals erfolgen soll
                            
                            Weiterhin werden MAX_LOG_FOLDER Unterordner im STATE_PATH erzeugt (N=0-9):
                            
                            * LogN.table        : enthält die table-HTML für ein basic-string (unescaped) Widget
                            * LogN.list         : enthält die list-HTML für ein basic-string (unescaped) Widget
                            * LogN.count        : Anzahl der Log-Zeilen (wenn das Log mit '/:error:|:warn:/' gefiltert ist, dann ist es die Anzahl der Fehler/Warnungen)
                            * LogN.filter       : Filter, der auch die logCache angewendet wurde im .table/.list zu erzeugen (siehe Filter)
                            * LogN.lastUpdate   : Timestamp des letzten Updates
                            
                            
                            ***** Filter
                            In den filter-States können sowohl strings (Bsp:'error') als auch RegExp-Strings (Bsp:'/warn|error/') 
                            hinterlegt werden. RegExp-Strings werden an den einschließenden  '/' erkannt. Über den ':' kann der Anfang
                            eines Feldes mit in den Filter einbezogen werden. 
                            Beispiele: 
                            '/Feiertag|Geburtstag/' (RegExp) zeigt alle Zeilen an, in denen 'Feiertag' oder 'Geburtstag' in irgendeinem Feld vorkommen
                            ':Abfall:' (string) zeigt alle Zeilen an, welche derKalendar 'Abfall' lautet
                            'Arzt' (string) zeigt alle Zeilen an, in denen 'Arzt' in irgendeinem Feld vorkommt
                            
                            **** Lizenz
                            (c) 2020 by UH, MIT License, no warranty, use on your own risc
                            
                            *** Changelog
                            2020.05.01 UH 
                            * Anpassung an neues MduiBase (intern)
                            * Anpassung an MDCSS 2.5
                            * Serientermine vor dem aktuellem Datum werden nicht mehr angezeigt
                            
                            */
                            
                            // ------------------------------------------------------------------------------------- 
                            // MduiBase
                            // ------------------------------------------------------------------------------------- 
                            
                            class MduiBase {
                            
                                constructor() {
                                  this.init();
                                }
                                
                                //
                                init() {
                                    // const
                                    this.DEBUG      = false;
                                    this.VERSION    = '1.0/2020-01-01';
                                    this.NAME       = 'mduiBase';
                                    this.STATE_PATH = '0_userdata.0.mdui.base.';
                                    this.STATE_UNKNOWN    =  0;
                                    this.STATE_INSTALLING = 10;
                                    this.STATE_INSTALLED  = 11;
                                    this.STATE_STARTING   = 20;
                                    this.STATE_STARTED    = 21;
                                    this.STATE_STOPPING   = 30;
                                    this.STATE_STOPPED    = 31;
                                
                                    // var
                                    this.state = this.STATE_UNKNOWN;
                                    this.states = [];
                                    this.subscribers = [];
                                    this.schedulers = [];
                                
                                    this.doInit();
                                
                                    // init der states
                                    this.states.push( { id:'version',     common:{name:'installed script-version', write:false, def:this.VERSION} } );
                                }
                                
                                //
                                // start the script/class
                                //
                                start() {
                                    // beim 1.Start nur die States erzeugen
                                    if ( !this.existState("version") || (this.getState('version').val!=this.VERSION) ) {
                                        for (let s=0; s<this.states.length; s++) { this.createState( this.states[s].id ); }
                                        this.logWarn('first script start, creating states for version '+this.VERSION+', automatic restarting script again in 10 sec ...');
                                        setStateDelayed(this.STATE_PATH + 'version', this.VERSION, 3000);
                                        setTimeout( this.start.bind(this), 10000 );
                                        this.state = this.STATE_INSTALLED; 
                                        return;
                                    }
                                    switch (this.state) {
                                        case this.STATE_UNKNOWN : ;
                                        case this.STATE_INSTALLING : ;
                                        case this.STATE_INSTALLED : ;
                                        case this.STATE_STOPPED : {
                                            this.state = this.STATE_STARTING; 
                                            if (this.doStart()) {
                                                this.log('script started');
                                                this.state = this.STATE_STARTED;
                                            }
                                            break;    
                                        }
                                        case this.STATE_STARTING : ;
                                        case this.STATE_STARTED : {
                                            this.logWarn('script already starting/started');
                                            break;    
                                        }
                                        case this.STATE_STOPPING : {
                                            this.logWarn('script is stopping, pls start later again');
                                            break;    
                                        }
                                  
                                    } 
                                }
                                
                                //
                                // stop the script/class
                                //
                                stop() {
                                    switch (this.state) {
                                        case this.STATE_STARTED : {
                                            this.state = this.STATE_STOPPING; 
                                            if (this.doStop()) {
                                                for (let i=0; i<this.subscribers.length; i++) if (this.subscribers[i] !== undefined) unsubscribe( this.subscribers[i] );
                                                this.subscribers = [];
                                                for (let i=0; i<this.schedulers.length; i++) if (this.schedulers[i] !== undefined) clearSchedule( this.schedulers[i] );
                                                this.schedulers = [];
                                                this.state = this.STATE_STOPPED; 
                                                this.log('script stopped');
                                            }
                                            break;    
                                        }
                                        default : {
                                            this.log('cant stopp script, because not startet');
                                        }
                                    } 
                                }
                                
                                //
                                // virtual functions, overwrite it 
                                //
                                doInit() { return true; }
                                doStart() { return true; }
                                doStop() { return true; }
                                
                                // einen on-Handler registrieren
                                subscribe( handler ) {
                                    this.subscribers.push( handler );
                                }
                                
                                // einen timer registrieren
                                schedule( handler ) {
                                    this.schedulers.push( handler );
                                }
                                
                                //
                                // tool functions 
                                //
                                logDebug(msg) { if (this.DEBUG) console.log('['+this.NAME+'] '+msg); }
                                log(msg) { console.log('['+this.NAME+'] '+msg); }
                                logWarn(msg) { console.warn('['+this.NAME+'] '+msg); }
                                logError(msg) { console.error('['+this.NAME+'] '+msg); }
                                
                                // über den $-Operator nachsehen, ob der state bereits vorhanden ist
                                // getState().notExists geht auch, erzeugt aber Warnmeldungen!
                                existState(id) {
                                    return ( $(this.STATE_PATH+id).length==0?false:true);
                                }
                                
                                // wrapper, adds statepath to state-ID
                                getState(id) {
                                    return getState(this.STATE_PATH + id);
                                }
                                
                                // like setState(), but adds statepath to state_ID and checks if state exists, when not, creates it
                                setState(id,value) {
                                    if ( !this.existState(id) ) this.createState(id,value,undefined);
                                    else setState( this.STATE_PATH + id, value);
                                }
                                
                                // like cresteState(), but adds statepath to state_ID and checks if state exists, when not, creates it
                                createState(id,value,common) {
                                    if ( !this.existState(id) ) {
                                        if (common===undefined) {
                                            // id im states-Array suchen
                                            for (var i=0; i<this.states.length; i++) { 
                                                if (this.states[i].id==id) {
                                                    if (this.states[i].hasOwnProperty('common'))
                                                        common = this.states[i].common;
                                                   break;
                                                }   
                                            }
                                        }
                                        if ( (typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
                                        // unter "0_userdata.0"
                                        let obj = {};
                                        obj.type = 'state';
                                        obj.native = {};
                                        obj.common = common;
                                        setObject(this.STATE_PATH + id, obj, (err) => {
                                                if (err) {
                                                    this.log('cant write object for state "' + this.STATE_PATH + id + '": ' + err);
                                                } else { 
                                                    this.log('state "' + this.STATE_PATH + id + '" created');
                                                }
                                        });
                                
                                        setTimeout( setState, 3000, this.STATE_PATH + id, value );
                                    }
                                }
                                
                                // true, if str contains filter string or regexp 
                                fitsFilter(str, filter) {
                                    if ( (filter===undefined) || !filter || (filter=='') )
                                        return true;
                                    if ( filter instanceof RegExp )  {
                                        if (str.match( filter ) != null) return true;
                                    } else if (typeof filter == 'string') {
                                        if(str.includes(filter)) return true;
                                    }
                                    return false;        
                                }
                                
                                //
                                escapeRegExp(str) {
                                    return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 
                                }
                                
                                // wandelt eine Farbe im hex-Format (#000000) in ein RGB-Array[2] um
                                hexToRGB(hex) {
                                    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
                                    return result 
                                        ? [parseInt(result[1],16),parseInt(result[2],16),parseInt(result[3],16)]
                                        : [0,0,0];
                                };
                                
                                // Helligkeit berechnen
                                getLuminance(r, g, b) {
                                    var a = [r, g, b].map(function (v) {
                                        v /= 255;
                                        return v <= 0.03928
                                            ? v / 12.92
                                            : Math.pow( (v + 0.055) / 1.055, 2.4 );
                                    });
                                    return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
                                }
                                
                                // Kontrats berechnen
                                getContrast(rgb1, rgb2) {
                                    var l1 = this.getLuminance(rgb1[0], rgb1[1], rgb1[2]) + 0.05;
                                    var l2 = this.getLuminance(rgb2[0], rgb2[1], rgb2[2]) + 0.05;
                                    if ( l1 > l2 ) return l1 / l2 
                                    else return l2 / l1;
                                }
                                
                                // liefert die fontColor auf Basis der backgroundColor durch Berechnung
                                // des Kontrasts
                                getFontColor(backgroundColor) {
                                    if ( this.getContrast(this.hexToRGB(backgroundColor),this.hexToRGB("#000000")) < 6 ) 
                                        return "#ffffff";
                                    else
                                        return "#000000";
                                }
                                
                                }
                                
                                // ------------------------------------------------------------------------------------- 
                                // MduiLogHMDevices
                                // ------------------------------------------------------------------------------------- 
                                
                                class MduiShowIcal extends MduiBase {
                                
                                constructor() {
                                    super();
                                }
                                
                                doInit() {
                                  super.doInit();
                                
                                  // const
                                  this.DEBUG = false;
                                  this.VERSION = '1.0/2020-03-22';
                                  this.NAME = 'mduiShowIcal';
                                  this.DAY_MILLISECONDS = 60 * 60 * 24 * 1000;
                                
                                  // -----------------------  
                                  // optional: KONFIGURATION
                                  // -----------------------  
                                                       // state-Pfad unter dem die States angelegt werden  
                                  this.STATE_PATH      = '0_userdata.0.mdui.showIcal.'; 
                                                       // Anzahl der Table/List Ordner mit eigenem Filter/View
                                  this.MAX_LOG_FOLDER  = 3;   
                                                       // max.Anzahl der Zeilen für die Table/List Ausgabe
                                  this.MAX_TABLE_ROWS  = 200; 
                                                       // Objekt-Pfad zum ical.x.data.table
                                  this.ICAL_TABLE      = 'ical.0.data.table';
                                                       // siehe: https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#formatdate
                                  this.DATE_FORMAT     = 'W DD.MM.YYYY hh:mm';
                                                       // optional können dem Kalendar noch Icons und abweichende
                                                       // Farben angegeben werden (diese überschreiben jene aus iCal)
                                                       // 'icon'     : 'Icon-Name' (MDCSS/Google WebFont)
                                                       // 'calColor' : *#rrggbb' abweichende Kalendarfarbe 
                                                       // 'ignore'   : true|false Kalendar komplett ignorieren
                                  this.CALENDAR        = {'mdui-Abfall'      : {'icon':'delete_outline', 'calcolor':'orange' },
                                                          'mdui-Geburtstage' : {'icon':'cake'},
                                                          'Familie'          : {'ignore':true}
                                                           
                                                         };
                                
                                  // -----------------------  
                                  // ENDE KONFIGURATION
                                  // -----------------------  
                                
                                  // var
                                  this.logs = [];
                                  for (let i=0; i<=this.MAX_LOG_FOLDER && i<10; i++) 
                                      this.logs.push({filter:'' });
                                  
                                
                                  // init der states
                                  this.states.push( { id:'version',     common:{name:'installed script-version', write:false, def:this.VERSION} } );
                                  this.states.push( { id:'updatePressed',common:{name:'update button pressed', write:true, type:'boolean', def:'false', role:'button' }} );
                                  
                                  let defFilter;
                                  for (let i=0; i<=this.MAX_LOG_FOLDER && i<10; i++) {
                                      switch (i) {
                                          case 1 : defFilter = ':Abfall:'; break;   
                                          case 2 : defFilter = 'Geburtstag'; break;   
                                          case 3 : defFilter = ''; break;   
                                          default: defFilter = undefined;
                                      }
                                      this.states.push( { id:'log'+i+'.table',      common:{name:'ioBroker-log as table', write:false, role:'html' }} );
                                      this.states.push( { id:'log'+i+'.list',       common:{name:'ioBroker-log as list', write:false, role:'html' }} );
                                      this.states.push( { id:'log'+i+'.count',      common:{name:'ioBroker-log count', write:false, type:'number', def:'0' }} );
                                      this.states.push( { id:'log'+i+'.filter',     common:{name:'ioBroker-log filter', write:true, def:defFilter}} );
                                      this.states.push( { id:'log'+i+'.lastUpdate', common:{name:'ioBroker-log last update', write:false, def:'0' }} );
                                  }
                                
                                  return true;  
                                }
                                
                                // start the script/class
                                doStart() {
                                    super.doStart();
                                    
                                    // subscriber erzeugen
                                    this.subscribe( on( this.STATE_PATH+'updatePressed', obj => { this.onUpdate(obj) } ));
                                    this.subscribe( on( new RegExp( this.STATE_PATH+'*.filter' ), obj => { this.onFilter(obj) } ));
                                    this.subscribe( on( this.ICAL_TABLE, obj => { this.onIcalTable(obj) } ));
                                
                                    this.onBuildHTML();
                                    return true;
                                }
                                
                                // stop the script/class
                                doStop() {
                                    super.doStop();
                                    return true;
                                }
                                
                                // 
                                onUpdate(obj) {
                                    if (obj.state.val===true) {
                                        this.onBuildHTML();
                                    }
                                    this.setState('updatePressed', false);
                                }
                                
                                // filter, sort events
                                onFilter(obj) {
                                  this.onBuildHTML();
                                }
                                
                                // Ical table hat sich geändert
                                onIcalTable(obj) {
                                  this.onBuildHTML();
                                }
                                
                                
                                
                                // creates the HTML states for every log
                                /*
                                'date' => "→ 16.10.2017" 
                                'event' => "9.30 - 16.30 Uhr Stopka " 
                                '_class' => "ical_Kerstin ical_today" 
                                '_date' => "2017-10-16T07:30:00.000Z" 
                                '_end' => "2017-10-16T14:30:00.000Z" 
                                '_section' => "" 
                                '_IDID' => "040000008200E00074C5B7101A82E008000000007645DC55A6DFC44FB2EC6FEA9EFEA33C100000007688316058136F42AD128D91103543C9" 
                                '_allDay' => "false" 
                                '_rule' => " " 
                                '_calName' => "Kerstin" 
                                
                                Optionen der ical-Instanz:
                                    'daysPreview' => "7"
                                    'colorize' => "false"
                                    'defColor' => "white"
                                    'fulltime' => " 00:00"
                                    'dataPaddingWithZeros' => "true"
                                    'replaceDates' => "false"
                                    'language' => "de"
                                    'everyCalOneColor' => "true"
                                    'calendars' (array) 
                                        '0' (array) 
                                            'name' => "Abfall"
                                            'url' => "https://calendar.google.com/calendar/ical/ruo0ddgalu03qq2ehpm8imqnk4%40group.calendar.google.com/private-a30aac0367f8b50cfd7373f6222d29b4/basic.ics"
                                            'user' => ""
                                            'pass' => ""
                                            'sslignore' => ""
                                            'color' => ""
                                */
                                
                                isSameDay(d1,d2) {
                                    return (d1.getDate()==d2.getDate()) && (d1.getMonth()==d2.getMonth()) && (d1.getFullYear()==d2.getFullYear());
                                }
                                
                                getWeekNumber( date ) {
                                    let d = new Date(date);
                                    d.setHours(0,0,0);
                                    d.setDate(d.getDate()+4-(d.getDay()||7));
                                    return Math.ceil((((d-new Date(d.getFullYear(),0,1))/8.64e7)+1)/7);
                                };            
                                
                                //
                                buildEntry( entry ) {
                                    const WEEKDAY_NAMES = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"];
                                    const MONTH_NAMES = ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"];
                                
                                    let beginDate = new Date( entry.beginDateISO );
                                    entry.beginTime = beginDate.getTime();
                                    entry.beginWeekDay = beginDate.getDay(); // 0=Sonntag 6=Samstag
                                    entry.beginWeekDayName = WEEKDAY_NAMES[entry.beginWeekDay]; 
                                    entry.beginDay = beginDate.getDate();
                                    entry.beginMonth = beginDate.getMonth();
                                    entry.beginMonthName = MONTH_NAMES[entry.beginMonth]; 
                                    entry.beginYear = beginDate.getFullYear();
                                    entry.beginHour = beginDate.getHours();
                                    entry.beginMinute = beginDate.getMinutes();
                                    entry.beginDate = formatDate(beginDate,  this.DATE_FORMAT);
                                
                                    let currDate = new Date( entry.currDateISO );
                                    entry.currTime = currDate.getTime();
                                    entry.currWeekDay = currDate.getDay(); // 0=Sonntag 6=Samstag
                                    entry.currWeekDayName = WEEKDAY_NAMES[entry.currWeekDay]; 
                                    entry.currDay = currDate.getDate();
                                    entry.currMonth = currDate.getMonth();
                                    entry.currMonthName = MONTH_NAMES[entry.currMonth]; 
                                    entry.currYear = currDate.getFullYear();
                                    entry.currHour = currDate.getHours();
                                    entry.currMinute = currDate.getMinutes();
                                    entry.currDate = formatDate(currDate,  this.DATE_FORMAT);
                                    entry.currDateOnly = entry.currYear*10000+entry.currMonth*100+entry.currDay;
                                
                                
                                    let endDate = new Date( entry.endDateISO );
                                    //allDay Korrektur: liefert immer einen Tag zu viel
                                    if (entry.allDay && endDate.getHours()==0) endDate.setTime( endDate.getTime() - this.DAY_MILLISECONDS);
                                    entry.endTime = endDate.getTime();
                                    entry.endWeekDay = endDate.getDay(); // 0=Sonntag 6=Samstag
                                    entry.endDay = endDate.getDate();
                                    entry.endMonth = endDate.getMonth();
                                    entry.endYear = endDate.getFullYear();
                                    entry.endHour = endDate.getHours();
                                    entry.endMinute = endDate.getMinutes();
                                    entry.endDate = formatDate(endDate, this.DATE_FORMAT);
                                
                                    // 
                                    if (entry.currWeekDay==0 || entry.currWeekDay==6) entry.dayColor = '#f44336'
                                    else entry.dayColor = 'inherited';
                                
                                    // 
                                    if (entry.currWeekDay==1) entry.week = this.getWeekNumber(currDate)+'.W';
                                    else entry.week = '';
                                
                                    // 
                                    if (entry.currTime < Date.now() ) entry.opacity = '.66'
                                    else entry.opacity = '1';
                                
                                    // Zeitraumangabe berechnen
                                    entry.hint = '';
                                    if ( !this.isSameDay(beginDate, endDate) ) {
                                            // mehrtägig
                                            if (entry.allDay)
                                                entry.timeSpan = 'ganztägig ';
                                            else if ( this.isSameDay(beginDate, currDate) ) 
                                                    entry.timeSpan = 'ab ' + formatDate(beginDate,'hh:mm');
                                                 else if ( this.isSameDay(endDate, currDate) ) 
                                                          entry.timeSpan = 'bis ' + formatDate(endDate,'hh:mm');
                                                      else 
                                                           entry.timeSpan = 'ganztägig ';
                                        } else {
                                            // an einem Tag
                                            if (entry.allDay)
                                                entry.timeSpan = 'ganztägig';
                                            else if ( (entry.beginHour!=entry.endHour) || (entry.beginMinute!=entry.endMinute)  ) 
                                                     entry.timeSpan = formatDate(beginDate,'hh:mm') + '-' + formatDate(endDate,'hh:mm');
                                                 else   
                                                     entry.timeSpan = formatDate(beginDate,'hh:mm');
                                        }
                                    return entry;        
                                };
                                
                                
                                onBuildHTML() { try {
                                
                                    let json = [];  
                                    let calTable = getState(this.ICAL_TABLE);
                                    let inst     = getObject("system.adapter."+this.ICAL_TABLE.substr(0,6));
                                    let instopt  = inst.native;
                                    let calendar = {};
                                    let cal      = {};
                                    let calOptions = {};
                                    let todayDate = new Date();
                                    let today = todayDate.getFullYear()*10000+todayDate.getMonth()*100+todayDate.getDate();
                                
                                
                                    for (var i = 0; i < calTable.val.length; i++) { 
                                      cal = calTable.val[i];
                                      let entry = {};
                                      if ( cal._calName != calendar.name ) {
                                            calendar = {};
                                            // color suchen
                                            for (let c = 0; c < instopt.calendars.length; c++ ) {
                                                if (cal._calName == instopt.calendars[c].name ) {
                                                    calendar = instopt.calendars[c];
                                                    break;
                                                }
                                            }
                                            // options suchen
                                            if (this.CALENDAR.hasOwnProperty(cal._calName)) calOptions = this.CALENDAR[cal._calName];
                                            else calOptions={};
                                        }    
                                        if (calOptions.hasOwnProperty('ignore') && calOptions.ignore ) continue;
                                
                                        if (calOptions.hasOwnProperty('calcolor')) entry.calColor = calOptions.calcolor;
                                        else if (calendar.color !== "") entry.calColor = calendar.color;
                                             else entry.calColor = '#000000';
                                        entry.color = this.getFontColor( entry.calColor ); 
                                        if (calOptions.hasOwnProperty('icon')) entry.icon = calOptions.icon;
                                        else entry.icon='';
                                
                                        entry.date = cal.date;
                                        entry.event = cal.event;
                                        entry.calName = cal._calName;
                                        entry.beginDateISO = cal._date;
                                        entry.currDateISO = cal._date;
                                        entry.endDateISO  = cal._end;
                                        entry.allDay  = cal._allDay; 
                                        entry.location = cal.location;
                                
                                        entry = this.buildEntry( entry);
                                
                                        if (entry.currDateOnly >= today)
                                            json.push( entry );
                                
                                        // Listenansicht
                                        // in calTable steht nur ein Eintrag für jeden Beginn, für die List-Darstellung
                                        // sind diese auch je Tag notwendig - hier jetzt bilden 
                                        if ( (entry.beginDay!=entry.endDay) || (entry.beginMonth!=entry.endMonth) || (entry.beginYear!=entry.endYear) ) {
                                            let currTime = new Date(entry.beginDateISO).getTime() + this.DAY_MILLISECONDS;
                                            let endTime = new Date(entry.endDateISO).getTime();
                                            if (entry.allDay) endTime -= + this.DAY_MILLISECONDS;
                                            let dayMax=Math.trunc( 2 + (endTime - currTime) /this. DAY_MILLISECONDS); 
                                            entry.hint += ' (Tag 1/'+dayMax+')';
                                            let dayCount=2; 
                                            while (currTime <= endTime && dayCount<100) {
                                                let newEntry = {};
                                                Object.assign(newEntry, entry);
                                                newEntry.currDateISO = new Date(currTime).toISOString();
                                                newEntry = this.buildEntry( newEntry );
                                                newEntry.hint += ' (Tag '+dayCount+'/'+dayMax+')';
                                                if (newEntry.currDateOnly >= today)
                                                    json.push( newEntry );
                                                currTime = currTime + this.DAY_MILLISECONDS;
                                                dayCount++;
                                            }
                                
                                        }
                                    }
                                
                                    // sortieren
                                    json.sort( (l,r) => {
                                              let lv=l['currTime'],rv=r['currTime'];
                                              return ((lv < rv) ? -1 : (lv > rv) ? 1 : 0);
                                          } );
                                        
                                  // build table/list HTML
                                  for (let i=0; i<=this.MAX_LOG_FOLDER && i<10; i++) {
                                      let log = this.logs[i];
                                      log.filter = '';
                                      log.ts = 0;
                                      log.idState = 'log'+i;
                                      if (this.existState(log.idState+'.filter')) log.filter = this.getState(log.idState+'.filter').val;
                                      if (this.existState(log.idState+'.lastClear')) log.ts = this.getState(log.idState+'.lastClear').val;
                                
                                      this.convertJSON2HTML(json, log);
                                  }
                                } catch(err) { this.logError( 'onBuildHTML: '+err.message ); }  }
                                
                                
                                // color date event calName beginDate endDate allDay
                                convertJSON2HTML(json, log) {
                                const tmpTable = {
                                header : 
                                `<tr>
                                <th style="text-align:right;"></th>
                                <th style="text-align:left;"></th>
                                <th style="text-align:left;"></th>
                                <th style="text-align:left;"></th>
                                <th style="text-align:left;"></th>
                                <th style="text-align:left; min-width:12em;">Betreff</th>
                                <th style="text-align:left;">Zeit</th>
                                <th style="text-align:left;">Ort</th>
                                <th style="text-align:left;">Kalendar</th>
                                <th style="text-align:left;"></th>
                                </tr>`,
                                row : 
                                `<tr>
                                <td style="text-align:right;">
                                   <span style="display:{showDay}; color:{dayColor}; font-size:1.5em; opacity:1; font-weight:bold;">{currDay}</span>
                                </td>
                                <td>
                                   <span style="display:{showDay}; font-size:0.8em; margin-top:0.3em; margin-left:4px; opacity:.8;">{currMonthName}</span>
                                </td>
                                <td>
                                   <span style="display:{showDay}; font-size:0.8em; margin-top:0.3em; opacity:.8;">{currWeekDayName}</span>
                                </td>
                                <td>
                                  <span style="display:inline-block; width:.8em; height:.8em; margin-top:0.3em; background:{calColor}; border-radius:50%;">&nbsp;</span>
                                </td>
                                <td>
                                  <i class='material-icons mdui-center {color}' style='font-size:1.2em;'>{icon}</i>
                                </td>
                                <td>{event}</td>
                                <td><span style="font-size:1.0em; opacity:.8;">{timeSpan} {hint}</span></td>
                                <td>{location}</td>
                                <td><span style="font-size:0.8em; opacity:.8;color:{calColor};">{calName}</span></td>
                                <td></td>
                                </tr>`
                                }
                                
                                const tmpList = {
                                row : 
                                `<div class="mdui-listitem" style="font-size:1em; width:100%; display:flex; opacity:{opacity};">
                                  <div style="min-width:3.5em;">
                                    <div style="display:{showDay}; color:{dayColor};">
                                      <span style="font-size:1.5em; opacity:1; font-weight:bold;">{currDay}</span>
                                      <span style="font-size:0.8em; margin:4px; opacity:.8;">{currMonthName}<br/>
                                      {currWeekDayName}</span>
                                    </div>
                                    <div style="display:{showDay}; text-align:right; font-size:0.6em; opacity:.6;">{week}</div>
                                  </div>
                                  <div style="min-width:1.2em;">
                                    <div style="width:.8em; height:.8em;  margin:.1em; text-align:center; background:{calColor}; border-radius:50%;">&nbsp;</div>
                                    <div class="mdui-icon" style="font-size:1.1em; text-align:center; margin-top:0.33em;">{icon}</div>
                                  </div>
                                  <div style="width:100%; margin-left:.25em;">
                                    <div style="">
                                      <div style="font-size:1.1em;">{event}</div>
                                    </div>
                                    <div style="width:100%; display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between;">
                                      <div style="font-size:1.0em; opacity:.8;">
                                        {timeSpan}
                                        <span style="font-size:0.8em;">{hint} {location}</span>
                                      </div>
                                      <div style="font-size:0.8em; opacity:.8;color:{calColor};">{calName}</div>
                                    </div>
                                  </div>
                                </div>`}
                                    // build htmlTable and htmlList
                                    let htmlTable  = "<table><thead>"+tmpTable.header+"</thead><tbody>";
                                    for (let [key, value] of Object.entries(log)) htmlTable = htmlTable.replace(new RegExp('{'+key+'}','g'),value);
                                   
                                    let htmlList  = "";
                                    let entry, tr;
                                    let count = 0;
                                    // filter as regex?
                                    if ( log.filter!==undefined && typeof log.filter == 'string' && log.filter.startsWith('/') && log.filter.endsWith('/') && (log.filter.length>=2) )  {
                                        log.filter = new RegExp(log.filter.substr(1,log.filter.length-2), 'i');
                                    }
                                
                                    let lastEntry = {};
                                    for (var i = 0; i < json.length && count<this.MAX_TABLE_ROWS; i++) { 
                                        entry = json[i];
                                        if (this.fitsFilter(':' + entry.currDate + ':' + entry.event +':'+entry.calName + ':' + entry.location + ':',log.filter)) {
                                            entry.showDay = (lastEntry=={}) || (entry.currDay!=lastEntry.currDay) || (entry.currMonth!=lastEntry.currMonth) || (entry.currYear!=lastEntry.currYear)?'flex':'none';
                                            lastEntry = entry;
                                            tr = tmpTable.row;    
                                            for (let [key, value] of Object.entries(entry)) tr = tr.replace(new RegExp('{'+key+'}','g'),value);
                                            htmlTable+=tr;
                                            tr = tmpList.row;    
                                            for (let [key, value] of Object.entries(entry)) tr = tr.replace(new RegExp('{'+key+'}','g'),value);
                                            htmlList+=tr;
                                            count++;
                                        }
                                    }
                                    htmlTable+="</body></table>";    
                                    this.setState(log.idState+'.table', htmlTable);  
                                    this.setState(log.idState+'.list', htmlList);  
                                    this.setState(log.idState+'.count', count);  
                                    this.setState(log.idState+'.lastUpdate', +new Date());  
                                }
                                
                                }
                                
                                
                                // create instance and start
                                var mduiShowIcal = new MduiShowIcal( );
                                mduiShowIcal.start();
                                
                                // on script stop, stop instance too
                                onStop(function () { 
                                    mduiShowIcal.stop(); 
                                }, 1000 );
                            
                            E Offline
                            E Offline
                            Ente
                            wrote on last edited by Ente
                            #44

                            @sigi234

                            Skript läuft. Vielen Dank.

                            Tut mir leid sigi. Wie bekomme ich das nun in meine vis integriert. Entschuldige bitte die Dummy-Frage.

                            sigi234S 1 Reply Last reply
                            0
                            • E Ente

                              @sigi234

                              Skript läuft. Vielen Dank.

                              Tut mir leid sigi. Wie bekomme ich das nun in meine vis integriert. Entschuldige bitte die Dummy-Frage.

                              sigi234S Online
                              sigi234S Online
                              sigi234
                              Forum Testing Most Active
                              wrote on last edited by
                              #45

                              @Ente sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                              @sigi234

                              Skript läuft. Vielen Dank.

                              Tut mir leid sigi. Wie bekomme ich das nun in meine vis integriert. Entschuldige bitte die Dummy-Frage.

                              Es werden States für n-Logs erzeugt, jedem, Log kann ein Standardfilter mitgegeben werden. In jedem Log-Ordner
                              befindet sich ein list-HTML State, welcher direkt in der vis angezeigt werden kann (jeweils im basic-string (unescaped) Widget).

                              Bitte benutzt das Voting rechts unten im Beitrag wenn er euch geholfen hat.
                              Immer Daten sichern!

                              E 1 Reply Last reply
                              0
                              • sigi234S sigi234

                                @Ente sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                @sigi234

                                Skript läuft. Vielen Dank.

                                Tut mir leid sigi. Wie bekomme ich das nun in meine vis integriert. Entschuldige bitte die Dummy-Frage.

                                Es werden States für n-Logs erzeugt, jedem, Log kann ein Standardfilter mitgegeben werden. In jedem Log-Ordner
                                befindet sich ein list-HTML State, welcher direkt in der vis angezeigt werden kann (jeweils im basic-string (unescaped) Widget).

                                E Offline
                                E Offline
                                Ente
                                wrote on last edited by Ente
                                #46

                                @sigi234 said in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                @Ente sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                @sigi234

                                Skript läuft. Vielen Dank.

                                Tut mir leid sigi. Wie bekomme ich das nun in meine vis integriert. Entschuldige bitte die Dummy-Frage.

                                Es werden States für n-Logs erzeugt, jedem, Log kann ein Standardfilter mitgegeben werden. In jedem Log-Ordner
                                befindet sich ein list-HTML State, welcher direkt in der vis angezeigt werden kann (jeweils im basic-string (unescaped) Widget).

                                Genau das habe ich gerade gefunden. Es zeigt auch die Termine an,

                                feb6d00b-f448-415c-a618-733025c42ac5-image.png

                                leider nicht so wie in dem Bild im 1. Post. bzw. wie hier:

                                https://forum.iobroker.net/topic/31635/vorlage-mdcss-v2-ical-kalendar-anzeigen/15
                                1ad94760-95e1-46fb-ac36-f89d3a9b77ad-image.png

                                Ich vermute mal, dass ich das im Skript selbst ändern muss. Mal sehen.

                                Edit: Das Datum erscheint schon einmal. Jetzt will ich noch die Farben ändern. Den Filter habe ich auch nicht.

                                sigi234S 1 Reply Last reply
                                0
                                • E Ente

                                  @sigi234 said in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                  @Ente sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                  @sigi234

                                  Skript läuft. Vielen Dank.

                                  Tut mir leid sigi. Wie bekomme ich das nun in meine vis integriert. Entschuldige bitte die Dummy-Frage.

                                  Es werden States für n-Logs erzeugt, jedem, Log kann ein Standardfilter mitgegeben werden. In jedem Log-Ordner
                                  befindet sich ein list-HTML State, welcher direkt in der vis angezeigt werden kann (jeweils im basic-string (unescaped) Widget).

                                  Genau das habe ich gerade gefunden. Es zeigt auch die Termine an,

                                  feb6d00b-f448-415c-a618-733025c42ac5-image.png

                                  leider nicht so wie in dem Bild im 1. Post. bzw. wie hier:

                                  https://forum.iobroker.net/topic/31635/vorlage-mdcss-v2-ical-kalendar-anzeigen/15
                                  1ad94760-95e1-46fb-ac36-f89d3a9b77ad-image.png

                                  Ich vermute mal, dass ich das im Skript selbst ändern muss. Mal sehen.

                                  Edit: Das Datum erscheint schon einmal. Jetzt will ich noch die Farben ändern. Den Filter habe ich auch nicht.

                                  sigi234S Online
                                  sigi234S Online
                                  sigi234
                                  Forum Testing Most Active
                                  wrote on last edited by sigi234
                                  #47

                                  @Ente

                                  Hast du die Vorlage heruntergeladen und als View importiert?

                                  https://github.com/Uhula/ioBroker-Material-Design-Style/tree/master/templates/MduiShowIcal

                                  Bitte benutzt das Voting rechts unten im Beitrag wenn er euch geholfen hat.
                                  Immer Daten sichern!

                                  E 1 Reply Last reply
                                  0
                                  • sigi234S sigi234

                                    @Ente

                                    Hast du die Vorlage heruntergeladen und als View importiert?

                                    https://github.com/Uhula/ioBroker-Material-Design-Style/tree/master/templates/MduiShowIcal

                                    E Offline
                                    E Offline
                                    Ente
                                    wrote on last edited by
                                    #48

                                    @sigi234 said in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                    @Ente

                                    Hast du die Vorlage heruntergeladen und als View importiert?

                                    https://github.com/Uhula/ioBroker-Material-Design-Style/tree/master/templates/MduiShowIcal

                                    Ja, den JS von MduiShowIcal_Tableview.json und als View importiert. Das Ergebnis, naja:

                                    0ac27e47-3617-4816-886a-1fdd63e62982-image.png

                                    Das ganze verstehe ich nicht. Das Anzeigen der Termine reicht.

                                    sigi234S 1 Reply Last reply
                                    0
                                    • E Ente

                                      @sigi234 said in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                      @Ente

                                      Hast du die Vorlage heruntergeladen und als View importiert?

                                      https://github.com/Uhula/ioBroker-Material-Design-Style/tree/master/templates/MduiShowIcal

                                      Ja, den JS von MduiShowIcal_Tableview.json und als View importiert. Das Ergebnis, naja:

                                      0ac27e47-3617-4816-886a-1fdd63e62982-image.png

                                      Das ganze verstehe ich nicht. Das Anzeigen der Termine reicht.

                                      sigi234S Online
                                      sigi234S Online
                                      sigi234
                                      Forum Testing Most Active
                                      wrote on last edited by
                                      #49

                                      @Ente

                                      Welche Version hast du von MDCSS ?

                                      Bitte benutzt das Voting rechts unten im Beitrag wenn er euch geholfen hat.
                                      Immer Daten sichern!

                                      E 1 Reply Last reply
                                      0
                                      • sigi234S sigi234

                                        @Ente

                                        Welche Version hast du von MDCSS ?

                                        E Offline
                                        E Offline
                                        Ente
                                        wrote on last edited by
                                        #50

                                        @sigi234 said in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                        @Ente

                                        Welche Version hast du von MDCSS ?

                                        Äh?? Wo finde ich das?

                                        sigi234S 1 Reply Last reply
                                        0
                                        • E Ente

                                          @sigi234 said in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                          @Ente

                                          Welche Version hast du von MDCSS ?

                                          Äh?? Wo finde ich das?

                                          sigi234S Online
                                          sigi234S Online
                                          sigi234
                                          Forum Testing Most Active
                                          wrote on last edited by
                                          #51

                                          @Ente sagte in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                          @sigi234 said in [Vorlage] MDCSS v2: ical Kalendar anzeigen:

                                          @Ente

                                          Welche Version hast du von MDCSS ?

                                          Äh?? Wo finde ich das?

                                          Screenshot (679)_LI.jpg

                                          Bitte benutzt das Voting rechts unten im Beitrag wenn er euch geholfen hat.
                                          Immer Daten sichern!

                                          E 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          807

                                          Online

                                          32.6k

                                          Users

                                          82.3k

                                          Topics

                                          1.3m

                                          Posts
                                          Community
                                          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                                          ioBroker Community 2014-2025
                                          logo
                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Home
                                          • Recent
                                          • Tags
                                          • Unread 0
                                          • Categories
                                          • Unreplied
                                          • Popular
                                          • GitHub
                                          • Docu
                                          • Hilfe