Metainformationen zur Seite
  •  

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
iobroker:countdown_script_fuer_vis1 [06.01.2026] koljaiobroker:countdown_script_fuer_vis1 [06.01.2026] (aktuell) kolja
Zeile 53: Zeile 53:
 ⚠️ NICHT kürzen, NICHT umformatieren ⚠️ NICHT kürzen, NICHT umformatieren
 <code> <code>
 +
 +<!-- ==========================================================
 +     VIS Subscribe-Block (Pflicht!)
 +     Jede OID, die du unten nutzt, MUSS hier stehen.
 +     ========================================================== -->
 +<div style="display:none;">
 +  {countdown.0.countdowns.Weihnachten.fullJson}
 +  {countdown.0.countdowns.Silvester.fullJson}
 +  {countdown.0.countdowns.SommerurlaubItalien.fullJson}
 +</div>
 +
 +<div style="text-align:center;">
 +  <div id="cd_text_xmas" style="font-size:28px;font-weight:700;line-height:1.15;">
 +    Lade...
 +  </div>
 +
 +  <div style="height:18px;"></div>
 +
 +  <div id="cd_text_ny" style="font-size:28px;font-weight:700;line-height:1.15;">
 +    Lade...
 +  </div>
 +</div>
  
 <script> <script>
Zeile 58: Zeile 80:
 { {
   /* ==========================================================   /* ==========================================================
-     KONFIGURATION – HIER ERWEITERN+     KONFIGURATION
      ========================================================== */      ========================================================== */
- 
-  const OID_1 = "countdown.0.countdowns.Weihnachten.fullJson"; 
-  const OID_2 = "countdown.0.countdowns.Silvester.fullJson"; 
-  const OID_3 = "countdown.0.countdowns.SommerurlaubItalien.fullJson"; 
  
   const EMPTY_TEXT = "…";   const EMPTY_TEXT = "…";
 +
 +  // Wenn TRUE: Stunden werden ausgeblendet, sobald days > 1
 +  // (für days === 1 werden Stunden weiterhin angezeigt)
 +  const HIDE_HOURS_IF_MORE_THAN_ONE_DAY = true;
 +
 +  // Wieviele Events sind AKTIV konfiguriert (max 8)
 +  const EVENT_COUNT = 3;
  
   /* ==========================================================   /* ==========================================================
-     HILFSFUNKTIONEN+     EVENT-DEFINITIONEN 
 +     TYPE: 
 +       1 = Weihnachten (Speziallogik) 
 +       2 = Silvester   (Speziallogik) 
 +       3 = Generisch   (Titel + Emoji) 
 +     ========================================================== */ 
 + 
 +  // ---------------- Event 1 ---------------- 
 +  const E1_OID   = "countdown.0.countdowns.Weihnachten.fullJson"; 
 +  const E1_TYPE  = 1; 
 +  const E1_TITLE = ""; 
 +  const E1_EMOJI = ""; 
 + 
 +  // ---------------- Event 2 ---------------- 
 +  const E2_OID   = "countdown.0.countdowns.Silvester.fullJson"; 
 +  const E2_TYPE  = 2; 
 +  const E2_TITLE = ""; 
 +  const E2_EMOJI = ""; 
 + 
 +  // ---------------- Event 3 ---------------- 
 +  const E3_OID   = "countdown.0.countdowns.SommerurlaubItalien.fullJson"; 
 +  const E3_TYPE  = 3; 
 +  const E3_TITLE = "Sommerurlaub Italien"; 
 +  const E3_EMOJI = "☀️🇮🇹"; 
 + 
 +  // ---------------- Event 4..8 (Vorlagen) ---------------- 
 +  const E4_OID   = ""; 
 +  const E4_TYPE  = 3; 
 +  const E4_TITLE = ""; 
 +  const E4_EMOJI = ""; 
 + 
 +  const E5_OID   = ""; 
 +  const E5_TYPE  = 3; 
 +  const E5_TITLE = ""; 
 +  const E5_EMOJI = ""; 
 + 
 +  const E6_OID   = ""; 
 +  const E6_TYPE  = 3; 
 +  const E6_TITLE = ""; 
 +  const E6_EMOJI = ""; 
 + 
 +  const E7_OID   = ""; 
 +  const E7_TYPE  = 3; 
 +  const E7_TITLE = ""; 
 +  const E7_EMOJI = ""; 
 + 
 +  const E8_OID   = ""; 
 +  const E8_TYPE  = 3; 
 +  const E8_TITLE = ""; 
 +  const E8_EMOJI = ""; 
 + 
 +  /* ========================================================== 
 +     HILFSFUNKTIONEN (VIS-safe formatiert)
      ========================================================== */      ========================================================== */
  
Zeile 74: Zeile 151:
   {   {
     const n = Number(x);     const n = Number(x);
-    if (Number.isFinite(n)) return n;+ 
 +    if (Number.isFinite(n)) 
 +    { 
 +      return n; 
 +    } 
     return fallback;     return fallback;
   }   }
Zeile 80: Zeile 162:
   function parseFullJson(val)   function parseFullJson(val)
   {   {
-    if (val === null || val === undefined || val === "") return null;+    if (val === null || val === undefined || val === "") 
 +    { 
 +      return null; 
 +    }
  
     try     try
Zeile 89: Zeile 174:
       {       {
         t = t.trim();         t = t.trim();
-        if (t.startsWith('"') && t.endsWith('"')) t = JSON.parse(t);+ 
 +        if (t.startsWith('"') && t.endsWith('"')) 
 +        { 
 +          t = JSON.parse(t); 
 +        } 
         return JSON.parse(t);         return JSON.parse(t);
       }       }
Zeile 108: Zeile 198:
   function dayWord(n)   function dayWord(n)
   {   {
-    if (n === 1) return "Tag";+    if (n === 1) 
 +    { 
 +      return "Tag"; 
 +    } 
     return "Tagen";     return "Tagen";
   }   }
Zeile 114: Zeile 208:
   function hourWord(n)   function hourWord(n)
   {   {
-    if (n === 1) return "Stunde";+    if (n === 1) 
 +    { 
 +      return "Stunde"; 
 +    } 
     return "Stunden";     return "Stunden";
   }   }
  
   /* ==========================================================   /* ==========================================================
-     RESTZEIT+     EVENT-ZUGRIFF (ohne Arrays/Objekte) 
 +     ========================================================== */ 
 + 
 +  function getOid(i) 
 +  { 
 +    if (i === 1) return E1_OID; 
 +    if (i === 2) return E2_OID; 
 +    if (i === 3) return E3_OID; 
 +    if (i === 4) return E4_OID; 
 +    if (i === 5) return E5_OID; 
 +    if (i === 6) return E6_OID; 
 +    if (i === 7) return E7_OID; 
 +    if (i === 8) return E8_OID; 
 + 
 +    return ""; 
 +  } 
 + 
 +  function getType(i) 
 +  { 
 +    if (i === 1) return E1_TYPE; 
 +    if (i === 2) return E2_TYPE; 
 +    if (i === 3) return E3_TYPE; 
 +    if (i === 4) return E4_TYPE; 
 +    if (i === 5) return E5_TYPE; 
 +    if (i === 6) return E6_TYPE; 
 +    if (i === 7) return E7_TYPE; 
 +    if (i === 8) return E8_TYPE; 
 + 
 +    return 0; 
 +  } 
 + 
 +  function getTitle(i) 
 +  { 
 +    if (i === 1) return E1_TITLE; 
 +    if (i === 2) return E2_TITLE; 
 +    if (i === 3) return E3_TITLE; 
 +    if (i === 4) return E4_TITLE; 
 +    if (i === 5) return E5_TITLE; 
 +    if (i === 6) return E6_TITLE; 
 +    if (i === 7) return E7_TITLE; 
 +    if (i === 8) return E8_TITLE; 
 + 
 +    return ""; 
 +  } 
 + 
 +  function getEmoji(i) 
 +  { 
 +    if (i === 1) return E1_EMOJI; 
 +    if (i === 2) return E2_EMOJI; 
 +    if (i === 3) return E3_EMOJI; 
 +    if (i === 4) return E4_EMOJI; 
 +    if (i === 5) return E5_EMOJI; 
 +    if (i === 6) return E6_EMOJI; 
 +    if (i === 7) return E7_EMOJI; 
 +    if (i === 8) return E8_EMOJI; 
 + 
 +    return ""; 
 +  } 
 + 
 +  /* ========================================================== 
 +     RESTZEIT / ABGELAUFEN
      ========================================================== */      ========================================================== */
  
Zeile 125: Zeile 283:
   {   {
     const d = parseFullJson(val);     const d = parseFullJson(val);
-    if (!d) return 999999999;+ 
 +    if (!d) 
 +    { 
 +      return 999999999; 
 +    }
  
     if (d.total && d.total.seconds !== undefined)     if (d.total && d.total.seconds !== undefined)
Zeile 142: Zeile 304:
   function isExpired(val)   function isExpired(val)
   {   {
-    return remainingSeconds(val) <= 0;+    return (remainingSeconds(val) <= 0);
   }   }
  
   /* ==========================================================   /* ==========================================================
-     RENDER-FUNKTIONEN+     FORMATTER: Zeittext mit optionalen Stunden 
 +     ---------------------------------------------------------- 
 +     Gibt nur den "Zeitanteil" zurück, z.B.: 
 +       - "3 Tagen" (wenn days>1 und hideHours aktiv) 
 +       - "1 Tag und 5 Stunden" 
 +     ========================================================== */ 
 + 
 +  function formatDaysHours(days, hours) 
 +  { 
 +    // Wenn konfiguriert: Stunden ausblenden sobald days > 1 
 +    if (HIDE_HOURS_IF_MORE_THAN_ONE_DAY) 
 +    { 
 +      if (days > 1) 
 +      { 
 +        return String(days) + " " + dayWord(days); 
 +      } 
 +    } 
 + 
 +    // Standard: Tage + Stunden 
 +    return String(days) + " " + dayWord(days) + " und " + String(hours) + " " + hourWord(hours); 
 +  } 
 + 
 +  /* ========================================================== 
 +     RENDERER
      ========================================================== */      ========================================================== */
  
Zeile 159: Zeile 344:
     }     }
  
-    if (!data) return EMPTY_TEXT;+    if (!data) 
 +    { 
 +      return EMPTY_TEXT; 
 +    }
  
-    const days  = safeNum(data.total.days, 0); +    const days  = safeNum((data.total && data.total.days !== undefined) ? data.total.days : data.days, 0); 
-    const hours = safeNum(data.total.hours, 0);+    const hours = safeNum((data.hours !== undefined) ? data.hours : (data.total ? data.total.hours : undefined), 0); 
 +    const words = (data.inWords && data.inWords.long) ? data.inWords.long : ""; 
 + 
 +    if (now.getMonth() === 11 && now.getDate() === 23) 
 +    { 
 +      return "🎅 Weihnachten morgen" + subline(words); 
 +    } 
 + 
 +    if (days >= 1) 
 +    { 
 +      return "🎁 Weihnachten in " + formatDaysHours(days, hours); 
 +    }
  
-    return "🎁 Weihnachten in + days + " " + dayWord(days) + +    return "🎄 Frohe Weihnachten 🎄";
-           " und " + hours + " " + hourWord(hours);+
   }   }
  
Zeile 178: Zeile 376:
     }     }
  
-    if (!data) return EMPTY_TEXT;+    if (now.getMonth(=== 0 && now.getDate() === 1) 
 +    { 
 +      return "🥂🎉 Frohes neues Jahr! 🎉🥂"; 
 +    }
  
-    const days  = safeNum(data.total.days, 0); +    if (!data) 
-    const hours = safeNum(data.total.hours, 0);+    { 
 +      return EMPTY_TEXT
 +    }
  
-    return "🕛 Silvester in " + days " " + dayWord(days) + +    const days  = safeNum((data.total && data.total.days !== undefined) ? data.total.days : data.days, 0); 
-           und " + hours + " " + hourWord(hours);+    const hours = safeNum((data.hours !== undefined) ? data.hours : (data.total ? data.total.hours : undefined), 0); 
 +    const words = (data.inWords && data.inWords.long) ? data.inWords.long : ""; 
 + 
 +    if (now.getMonth() === 11 && now.getDate() === 30) 
 +    { 
 +      return "🎆 Silvester morgen" + subline(words); 
 +    } 
 + 
 +    if (days >= 1) 
 +    { 
 +      return "🕛 Silvester in " + formatDaysHours(days, hours); 
 +    } 
 + 
 +    return "🎇 Silvester heute" + subline(words);
   }   }
  
Zeile 190: Zeile 406:
   {   {
     const data = parseFullJson(val);     const data = parseFullJson(val);
-    if (!data) return EMPTY_TEXT; 
  
-    const days  = safeNum(data.total.days, 0); +    if (!data) 
-    const hours = safeNum(data.total.hours, 0);+    { 
 +      return EMPTY_TEXT
 +    }
  
-    return emoji + " " + title + " in " + days + " " + dayWord(days) + +    const days  = safeNum((data.total && data.total.days !== undefined? data.total.days : data.days, 0); 
-           " und " + hours + " " + hourWord(hours); +    const hours = safeNum((data.hours !== undefined) ? data.hours : (data.total ? data.total.hours : undefined), 0); 
-  }+    const words = (data.inWords && data.inWords.long) ? data.inWords.long : "";
  
-  /* ========================================================== +    if (days === 1) 
-     EVENTS (KONFIGURIERBAR+    { 
-     ========================================================== */+      return emoji + " " + title + " morgen" + subline(words); 
 +    }
  
-  const E1_OID OID_1+    if (days >1) 
-  const E2_OID = OID_2+    { 
-  const E3_OID = OID_3;+      return emoji + " " + title + " in " + formatDaysHours(days, hours)
 +    } 
 + 
 +    if (words) 
 +    { 
 +      return emoji + " " + title + subline(words)
 +    } 
 + 
 +    return emoji + " " + title + " bald"; 
 +  }
  
-  function renderEvent(i, val)+  function renderByIndex(i, val)
   {   {
-    if (i === 1) return renderWeihnachten(val); +    const t = getType(i); 
-    if (=== 2) return renderSilvester(val); + 
-    if (i === 3) return renderGeneric(val, "Sommerurlaub Italien""☀️🇮🇹")+    if (t === 1) 
-    return EMPTY_TEXT;+    { 
 +      return renderWeihnachten(val); 
 +    } 
 + 
 +    if (=== 2) 
 +    { 
 +      return renderSilvester(val); 
 +    
 + 
 +    return renderGeneric(val, getTitle(i)getEmoji(i));
   }   }
  
-  function pickTwo()+  /* ========================================================== 
 +     AUSWAHL: 2 nächste Events 
 +     ========================================================== */ 
 + 
 +  function pickTwoUpcoming()
   {   {
-    let b1 = -1; +    let best1_i = -1; 
-    let b2 = -1; +    let best1_r = 999999999;
-    let r1 = 999999999; +
-    let r2 = 999999999;+
  
-    let r;+    let best2_i = -1; 
 +    let best2_r = 999999999;
  
-    remainingSeconds(vis.states.attr(E1_OID + ".val"))+    let i 1; 
-    if (!isExpired(vis.states.attr(E1_OID + ".val")) && r r1)+ 
 +    while (<= EVENT_COUNT)
     {     {
-      r2 r1b2 b1+      const oid getOid(i); 
-      r1 = r;  b1 = 1;+ 
 +      if (oid) 
 +      { 
 +        const val vis.states.attr(oid + ".val")
 + 
 +        if (!isExpired(val)) 
 +        { 
 +          const r remainingSeconds(val); 
 + 
 +          if (< best1_r) 
 +          { 
 +            best2_i = best1_i; 
 +            best2_r = best1_r; 
 + 
 +            best1_i = i; 
 +            best1_r = r; 
 +          } 
 +          else 
 +          { 
 +            if (r < best2_r) 
 +            { 
 +              best2_i = i; 
 +              best2_r = r; 
 +            } 
 +          } 
 +        } 
 +      } 
 + 
 +      i i + 1;
     }     }
  
-    r = remainingSeconds(vis.states.attr(E2_OID + ".val")); +    return String(best1_i) + "|+ String(best2_i); 
-    if (!isExpired(vis.states.attr(E2_OID + ".val")) && r < r1)+  } 
 + 
 +  function renderSlot(slotIndex, el) 
 +  { 
 +    const picks = pickTwoUpcoming().split("|")
 +    let idx = -1; 
 + 
 +    if (slotIndex === 1)
     {     {
-      r2 r1; b2 = b1+      idx Number(picks[0]); 
-      r1 = r;  b1 2;+    } 
 +    else 
 +    { 
 +      idx Number(picks[1]);
     }     }
  
-    r = remainingSeconds(vis.states.attr(E3_OID + ".val")); +    if (idx 1)
-    if (!isExpired(vis.states.attr(E3_OID + ".val")) && r r2)+
     {     {
-      b2 3;+      el.innerHTML EMPTY_TEXT; 
 +      return;
     }     }
  
-    return String(b1) + "|+ String(b2);+    const oid = getOid(idx)
 +    const val = vis.states.attr(oid + ".val"); 
 + 
 +    el.innerHTML = renderByIndex(idx, val);
   }   }
 +
 +  /* ==========================================================
 +     START & BINDING
 +     ========================================================== */
  
   function start()   function start()
Zeile 252: Zeile 537:
     const el2 = document.getElementById("cd_text_ny");     const el2 = document.getElementById("cd_text_ny");
  
-    function update()+    if (typeof vis !== "undefined" && vis.states && el1 && el2)
     {     {
-      const p = pickTwo().split("|");+      function updateSlot1() 
 +      { 
 +        renderSlot(1, el1); 
 +      }
  
-      const v1 = vis.states.attr((p[0] === "1" ? E1_OID : p[0] === "2" ? E2_OID : E3_OID+ ".val"); +      function updateSlot2() 
-      const v2 = vis.states.attr((p[1] === "1" ? E1_OID : p[1] === "2" ? E2_OID : E3_OID) + ".val");+      
 +        renderSlot(2, el2); 
 +      }
  
-      el1.innerHTML = renderEvent(Number(p[0]), v1); +      if (E1_OID) vis.states.bind(E1_OID + ".val", updateSlot1); 
-      el2.innerHTML = renderEvent(Number(p[1]), v2); +      if (E2_OIDvis.states.bind(E2_OID + ".val"updateSlot1); 
-    }+      if (E3_OID) vis.states.bind(E3_OID + ".val", updateSlot1); 
 +      if (E4_OIDvis.states.bind(E4_OID + ".val"updateSlot1); 
 +      if (E5_OID) vis.states.bind(E5_OID + ".val", updateSlot1); 
 +      if (E6_OID) vis.states.bind(E6_OID + ".val", updateSlot1); 
 +      if (E7_OID) vis.states.bind(E7_OID + ".val", updateSlot1); 
 +      if (E8_OID) vis.states.bind(E8_OID + ".val", updateSlot1);
  
-    vis.states.bind(E1_OID + ".val", update); +      if (E1_OID) vis.states.bind(E1_OID + ".val", updateSlot2); 
-    vis.states.bind(E2_OID + ".val", update); +      if (E2_OID) vis.states.bind(E2_OID + ".val", updateSlot2); 
-    vis.states.bind(E3_OID + ".val", update);+      if (E3_OID) vis.states.bind(E3_OID + ".val", updateSlot2); 
 +      if (E4_OID) vis.states.bind(E4_OID + ".val", updateSlot2); 
 +      if (E5_OID) vis.states.bind(E5_OID + ".val", updateSlot2); 
 +      if (E6_OID) vis.states.bind(E6_OID + ".val", updateSlot2); 
 +      if (E7_OID) vis.states.bind(E7_OID + ".val", updateSlot2); 
 +      if (E8_OID) vis.states.bind(E8_OID + ".val", updateSlot2);
  
-    update();+      updateSlot1(); 
 +      updateSlot2(); 
 +    } 
 +    else 
 +    { 
 +      setTimeout(start, 300); 
 +    }
   }   }
  
Zeile 281: Zeile 587:
 })(); })();
 </script> </script>
 +
  
 </code> </code>