PageSourceSearch

https://www.greece-islands.co.il/js/weather-forecast.js?8:16:35%20PM

js greece-islands.co.il collected 2026-10-02 08:11:29 UTC 9,770 bytes, 199 lines download raw bytes

1/* ============================================================
2   תחזית מזג אוויר ליוון — סקריפט הטמעה חיצוני
3   נתונים: Open-Meteo (https://open-meteo.com) — חינמי, ללא מפתח API
4   RTL / עברית / צלזיוס / יוון בלבד / Bootstrap 3.4.x
5
6   הטמעה בדף:
7     <div id="wx-widget" data-default-city="אתונה" data-days="6"></div>
8     <script src="/js/weather-forecast.js" defer></script>
9
10   דרישות:
11   • הדף כבר טוען Bootstrap 3 (כמו באתר) — הסקריפט משתמש ב-panel/form-control/list-group.
12   • הדף מוגש כ-UTF-8 (כדי שהעברית תוצג נכון).
13   ============================================================ */
14(function () {
15  "use strict";
16
17  function init() {
18    var el = document.getElementById("wx-widget");
19    if (!el) { console.warn('[weather] לא נמצא אלמנט עוגן <div id="wx-widget">'); return; }
20    if (el.getAttribute("data-wx-ready")) return;   // מניעת אתחול כפול
21    el.setAttribute("data-wx-ready", "1");
22
23    injectStyleOnce();
24
25    el.setAttribute("dir", "rtl");
26    el.innerHTML =
27      '<div class="panel wx-panel"><div class="panel-body">' +
28        '<div class="wx-search">' +
29          '<input type="text" class="form-control wx-input" dir="auto" autocomplete="off" ' +
30                 'placeholder="חיפוש עיר ביוון (עברית או אנגלית)…" aria-label="חיפוש עיר ביוון">' +
31          '<ul class="list-group wx-suggest" role="listbox"></ul>' +
32        '</div>' +
33        '<div class="wx-body"><div class="wx-msg">טוען…</div></div>' +
34      '</div></div>';
35
36    run(el);
37  }
38
39  function injectStyleOnce() {
40    if (document.getElementById("wx-style")) return;
41    var s = document.createElement("style");
42    s.id = "wx-style";
43    s.textContent = [
44      '#wx-widget{font-family:"Segoe UI","Arial Hebrew",Arial,sans-serif;max-width:660px;direction:rtl}',
45      '#wx-widget .wx-panel{background: linear-gradient(150deg, #0d5eb0, #ffffff);color:#fff;border:none;border-radius:14px;box-shadow:0 12px 30px rgba(14,42,71,.35)}',
46      '#wx-widget .wx-search{position:relative;margin-bottom:16px}',
47      '#wx-widget .wx-suggest{position:absolute;top:100%;right:0;left:0;z-index:1000;margin-top:4px;max-height:230px;overflow-y:auto;display:none;box-shadow:0 10px 24px rgba(0,0,0,.25)}',
48      '#wx-widget .wx-suggest.open{display:block}',
49      '#wx-widget .wx-suggest .list-group-item{cursor:pointer;text-align:right;padding:9px 14px;color:#16385a}',
50      '#wx-widget .wx-suggest .list-group-item.active{background-color:#1b4a73;border-color:#1b4a73;color:#fff}',
51      '#wx-widget .wx-msg{color:rgba(255,255,255,.75);font-size:14px;padding:6px 2px}',
52      '#wx-widget .wx-now{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px}',
53      '#wx-widget .wx-place{font-size:17px;font-weight:600}',
54      '#wx-widget .wx-now-desc{font-size:13px;color:rgba(255,255,255,.75);margin-top:2px}',
55      '#wx-widget .wx-now-temp{font-size:44px;font-weight:700;line-height:1}',
56      '#wx-widget .wx-now-temp .u{font-size:20px;color:#ffd166}',
57      '#wx-widget .wx-now-icon{font-size:40px;line-height:1}',
58      '#wx-widget .wx-days{display:flex;gap:6px;border-top:1px solid rgba(255,255,255,.15);padding-top:14px}',
59      '#wx-widget .wx-day{flex:1;text-align:center}',
60      '#wx-widget .wx-day .d{font-size:12px;color:rgba(255,255,255,.75);font-weight:600}',
61      '#wx-widget .wx-day .i{font-size:24px;margin:5px 0}',
62      '#wx-widget .wx-day .t{font-size:13px;font-weight:600}',
63      '#wx-widget .wx-day .t .lo{color:rgba(255,255,255,.7);font-weight:400}',
64      '#wx-widget .wx-day .p{font-size:11px;color:#7fb8e6;margin-top:3px}'
65    ].join("");
66    document.head.appendChild(s);
67  }
68
69  function run(el) {
70    var input  = el.querySelector(".wx-input");
71    var sugBox = el.querySelector(".wx-suggest");
72    var body   = el.querySelector(".wx-body");
73
74    var days    = Math.min(parseInt(el.getAttribute("data-days"), 10) || 6, 7);
75    var defCity = el.getAttribute("data-default-city") || "אתונה";
76
77    var codes = {
78      0:["☀️","בהיר"], 1:["🌤️","בהיר ברובו"], 2:["⛅","מעונן חלקית"],
79      3:["☁️","מעונן"], 45:["🌫️","ערפל"], 48:["🌫️","ערפל"],
80      51:["🌦️","טפטוף קל"], 53:["🌦️","טפטוף"], 55:["🌧️","טפטוף חזק"],
81      61:["🌦️","גשם קל"], 63:["🌧️","גשם"], 65:["🌧️","גשם חזק"],
82      71:["🌨️","שלג קל"], 73:["🌨️","שלג"], 75:["❄️","שלג כבד"],
83      80:["🌦️","ממטרים"], 81:["🌧️","ממטרים"], 82:["⛈️","ממטרים חזקים"],
84      95:["⛈️","סופת רעמים"], 96:["⛈️","סופה"], 99:["⛈️","סופה עזה"]
85    };
86
87    function dayName(iso) {
88      return new Date(iso + "T00:00").toLocaleDateString("he-IL", { weekday: "short" });
89    }
90    function msg(t) { body.innerHTML = '<div class="wx-msg">' + t + "</div>"; }
91
92    function render(place, cur, daily) {
93      var c = codes[cur.weather_code] || ["🌡️", "—"];
94      var html =
95        '<div class="wx-now">' +
96          '<div><div class="wx-place" dir="auto">' + place + '</div>' +
97          '<div class="wx-now-desc">' + c[1] + '</div></div>' +
98          '<div style="display:flex;align-items:center;gap:10px">' +
99            '<span class="wx-now-icon">' + c[0] + '</span>' +
100            '<span class="wx-now-temp">' + Math.round(cur.temperature_2m) +
101              '<span class="u">°C</span></span>' +
102          '</div>' +
103        '</div><div class="wx-days">';
104      for (var i = 0; i < days && i < daily.time.length; i++) {
105        var di = (codes[daily.weather_code[i]] || ["🌡️"])[0];
106        var label = i === 0 ? "היום" : dayName(daily.time[i]);
107        var pop = daily.precipitation_probability_max[i];
108        html +=
109          '<div class="wx-day">' +
110            '<div class="d">' + label + '</div>' +
111            '<div class="i">' + di + '</div>' +
112            '<div class="t">' + Math.round(daily.temperature_2m_max[i]) +
113              '° <span class="lo">' + Math.round(daily.temperature_2m_min[i]) + '°</span></div>' +
114            '<div class="p">' + (pop != null ? "💧" + pop + "%" : "&nbsp;") + '</div>' +
115          '</div>';
116      }
117      body.innerHTML = html + "</div>";
118    }
119
120    function loadWeather(lat, lon, place) {
121      msg("טוען את " + place + "…");
122      var u = "https://api.open-meteo.com/v1/forecast?latitude=" + lat + "&longitude=" + lon +
123        "&current=temperature_2m,weather_code" +
124        "&daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_probability_max" +
125        "&forecast_days=" + days + "&temperature_unit=celsius&timezone=auto";
126      fetch(u).then(function (r) { return r.json(); })
127        .then(function (d) { render(place, d.current, d.daily); })
128        .catch(function () { msg("לא ניתן לטעון את התחזית. נסה שוב."); });
129    }
130
131    function langFor(q) { return /[\u0590-\u05FF]/.test(q) ? "he" : "en"; }
132
133    function geocode(name, lang) {
134      return fetch(
135        "https://geocoding-api.open-meteo.com/v1/search?count=10&language=" +
136        (lang || "he") + "&name=" + encodeURIComponent(name)
137      ).then(function (r) { return r.json(); })
138       .then(function (j) {
139          return (j.results || []).filter(function (c) { return c.country_code === "GR"; }).slice(0, 6);
140       });
141    }
142
143    function pick(c) {
144      sugBox.classList.remove("open");
145      sugBox.innerHTML = "";
146      input.value = c.name;
147      loadWeather(c.latitude, c.longitude, c.name);
148    }
149
150    var timer, active = -1, results = [];
151
152    input.addEventListener("input", function () {
153      clearTimeout(timer);
154      var q = input.value.trim();
155      if (q.length < 2) { sugBox.classList.remove("open"); return; }
156      timer = setTimeout(function () {
157        geocode(q, langFor(q)).then(function (res) {
158          results = res; active = -1;
159          if (!results.length) { sugBox.classList.remove("open"); return; }
160          sugBox.innerHTML = results.map(function (c, i) {
161            return '<li class="list-group-item" role="option" dir="auto" data-i="' + i + '">' +
162                   c.name + '</li>';
163          }).join("");
164          sugBox.classList.add("open");
165        });
166      }, 250);
167    });
168
169    sugBox.addEventListener("click", function (e) {
170      var li = e.target.closest("li");
171      if (li) pick(results[+li.getAttribute("data-i")]);
172    });
173
174    input.addEventListener("keydown", function (e) {
175      var items = [].slice.call(sugBox.querySelectorAll("li"));
176      if (!sugBox.classList.contains("open") || !items.length) return;
177      if (e.key === "ArrowDown") { active = (active + 1) % items.length; e.preventDefault(); }
178      else if (e.key === "ArrowUp") { active = (active - 1 + items.length) % items.length; e.preventDefault(); }
179      else if (e.key === "Enter") { if (active >= 0) pick(results[active]); e.preventDefault(); return; }
180      else if (e.key === "Escape") { sugBox.classList.remove("open"); return; }
181      items.forEach(function (it, i) { it.classList.toggle("active", i === active); });
182    });
183
184    document.addEventListener("click", function (e) {
185      if (!el.contains(e.target)) sugBox.classList.remove("open");
186    });
187
188    geocode(defCity, langFor(defCity)).then(function (r) {
189      if (r.length) { input.value = r[0].name; pick(r[0]); }
190      else msg('עיר ברירת המחדל "' + defCity + '" לא נמצאה.');
191    });
192  }
193
194  if (document.readyState === "loading") {
195    document.addEventListener("DOMContentLoaded", init);
196  } else {
197    init();
198  }
199})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.