1/* Pogoda â ÑÑонÑова логÑка вÑджеÑÑв. 2 * Ðогода: пеÑÐµÐ¼Ð¸ÐºÐ°Ñ Ð¼ÑÑÑ (вибÑÑ Ñ localStorage), геолокаÑÑÑ Ð²ÑдвÑдÑваÑа 3 * (кнопка або авÑо; кооÑдинаÑи Ñ localStorage до змÑни мÑÑÑа вÑÑÑнÑ), 4 * доÑÑгÑÐ²Ð°Ð½Ð½Ñ ÑвÑÐ¶Ð¸Ñ Ð´Ð°Ð½Ð¸Ñ ÑеÑез REST, коли ÑеÑвеÑний ÑÐµÐ½Ð´ÐµÑ Ð·Ð°ÑÑаÑÑв 5 * (ÐºÐµÑ ÑÑоÑÑнок). ÐÑÑаÑи: Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿ÑÑÐ»Ñ TTL. ÐÑÑÑ Ð²Ð°Ð»ÑÑ Ñ Ð¼ÐµÑали: Ñе Ñаме 6 * пÑÑÐ»Ñ TTL. ÐонвеÑÑеÑ: ÑÐ°Ñ Ñнок Ñ Ð±ÑаÑзеÑÑ Ð·Ð° кÑÑÑами Ð·Ñ ÑÑоÑÑнки. ÐаÑÑа: 7 * заванÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð·Ð° клÑком. 8 * ÐлаваÑÑÑ Ð¿Ð»Ð°Ñки: закÑиÑÑÑ Ð´Ð¾ кÑнÑÑ ÑеÑÑÑ (окÑемо Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ вÑджеÑа); 9 * на ÑелеÑÐ¾Ð½Ñ Ð¹ планÑеÑÑ (â¤1023px) â док: плаÑки ÑÑ Ð¾Ð²Ð°Ð½Ñ, Ð²Ð½Ð¸Ð·Ñ ÑÑдок вкладок, доÑик 10 * вÑдкÑÐ¸Ð²Ð°Ñ Ð¾Ð´Ð½Ñ Ð¿Ð»Ð°ÑкÑ, â Ñ ÑÑÐ´ÐºÑ Ñ Ð¾Ð²Ð°Ñ Ð´Ð¾Ðº до кÑнÑÑ ÑеÑÑÑ. */ 11(function () { 12 'use strict'; 13 var cfg = window.pogodaCfg || {}; 14 var KEY_CITY = 'pogoda_city'; 15 var KEY_GEO = 'pogoda_geo'; 16 var KEY_GEO_DENIED = 'pogoda_geo_denied'; 17 18 function store(kind, key, value) { 19 try { 20 var s = kind === 'session' ? window.sessionStorage : window.localStorage; 21 if (value === undefined) { return s.getItem(key); } 22 if (value === null) { s.removeItem(key); return null; } 23 s.setItem(key, value); 24 } catch (e) { /* пÑиваÑний Ñежим / вимкнене ÑÑ Ð¾Ð²Ð¸Ñе */ } 25 return null; 26 } 27 function q(el, sel) { return el.querySelector(sel); } 28 function setText(el, sel, text) { 29 var n = q(el, sel); 30 if (n) { n.textContent = text == null ? '' : text; } 31 } 32 /* Ðаголовок плаÑки. У бÑÑнÑй колонÑÑ Ð· ÑвÑмкненим виглÑдом його малÑÑ Ñема: 33 вÑн ÑÑоÑÑÑ ÐÐÐ ÐРплаÑÐºÐ¾Ñ (data-native="1") Ñ ÑозмÑÑÑÑ before_title Ñеми, 34 без наÑÐ¸Ñ ÐºÐ»Ð°ÑÑв â оновлÑÑмо пеÑÑий непоÑожнÑй ÑекÑÑовий вÑзол. */ 35 function setTitle(card, sel, text, d) { 36 if (text == null || text === '') { return; } 37 if (card.getAttribute('data-native') !== '1') { setText(card, sel, text); return; } 38 // ÐаÑивний заголовок коÑоÑкий (без даÑи) â даÑа ÑÑоÑÑÑ Ð¿ÑдпиÑом Ñ ÐºÐ°ÑÑÑÑ. 39 var dateEl = q(card, '.pogoda-head-date'); 40 if (dateEl && d && d.title_short) { 41 text = d.title_short; 42 if (d.date_label) { dateEl.textContent = d.date_label; } 43 } 44 if (!document.createTreeWalker) { return; } 45 // after_title Ñеми може закÑнÑÑваÑиÑÑ Ð´ÐµÐºÐ¾ÑаÑивним елеменÑом без ÑекÑÑÑ 46 // (лÑнÑÑ Ð¿Ñд заголовком) â ÑÐ¾Ð´Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº на один-два елеменÑи ÑанÑÑе. 47 var host = card.previousElementSibling; 48 for (var hop = 0; host && hop < 3; hop++, host = host.previousElementSibling) { 49 if (host.classList && host.classList.contains('pogoda')) { return; } // Ñе вже ÑÑÑÑÐ´Ð½Ñ Ð¿Ð»Ð°Ñка 50 var walker = document.createTreeWalker(host, 4 /* NodeFilter.SHOW_TEXT */, null, false); 51 var node; 52 while ((node = walker.nextNode())) { 53 if (node.nodeValue && node.nodeValue.replace(/\s+/g, '') !== '') { node.nodeValue = text; return; } 54 } 55 } 56 } 57 function restUrl(base, params) { 58 var qs = []; 59 for (var k in params) { 60 if (Object.prototype.hasOwnProperty.call(params, k) && params[k] !== undefined && params[k] !== null) { 61 qs.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k])); 62 } 63 } 64 return base + (base.indexOf('?') > -1 ? '&' : '?') + qs.join('&'); 65 } 66 function getJSON(url) { 67 return fetch(url, { credentials: 'omit', headers: { 'Accept': 'application/json' } }) 68 .then(function (r) { return r.ok ? r.json() : null; }); 69 } 70 /* Ðова плаÑки â паÑамеÑÑ lang кожного REST-запиÑÑ: адÑеÑа /wp-json/â¦ Ð¼Ð¾Ð²Ð½Ð¾Ñ 71 веÑÑÑÑ Ð½Ðµ маÑ, а пÑдпиÑи Ñ Ð²ÑдповÑÐ´Ñ Ð¿ÑÐ¸Ñ Ð¾Ð´ÑÑÑ Ð³Ð¾Ñовими. Ðез ÑÑого плаÑка 72 на /ru/ пÑÑÐ»Ñ Ñонового Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑÑавала Ð½Ð°Ð¿Ð¾Ð»Ð¾Ð²Ð¸Ð½Ñ ÑкÑаÑнÑÑкоÑ. */ 73 function withLang(card, params) { 74 var lang = card.getAttribute('data-lang'); 75 if (lang) { params.lang = lang; } 76 return params; 77 } 78 function isExpired(card) { 79 var ts = parseInt(card.getAttribute('data-ts'), 10) || 0; 80 var ttl = parseInt(card.getAttribute('data-ttl'), 10) || 1800; 81 return (Date.now() / 1000 - ts) > ttl || card.classList.contains('pogoda-stale') || card.classList.contains('pogoda-unavailable'); 82 } 83 84 /* ââ Ðогода ââ */ 85 function applyWeather(card, d) { 86 var f = d.fmt || {}; 87 card.classList.toggle('pogoda-unavailable', !d.ok); 88 card.classList.toggle('pogoda-stale', !!d.stale);
89 card.setAttribute('data-ts', String(d.fetched_at || 0)); 90 var icon = q(card, '.pogoda-main-icon-wrap'); 91 if (icon && f.icon_svg) { icon.innerHTML = f.icon_svg; } 92 setText(card, '.pogoda-temp', f.temp || 'â'); 93 setText(card, '.pogoda-wind .pogoda-val', f.wind); 94 setText(card, '.pogoda-wind-dir', f.wind_dir); 95 setText(card, '.pogoda-humidity .pogoda-val', f.humidity); 96 setText(card, '.pogoda-pressure .pogoda-val', f.pressure); 97 setText(card, '.pogoda-desc', f.desc); 98 setText(card, '.pogoda-feels-val', f.feels); 99 var feels = q(card, '.pogoda-feels'); 100 if (feels) { feels.hidden = !d.ok; } 101 var sel = q(card, '.pogoda-city-select'); 102 if (d.geo) { 103 card.classList.add('pogoda-is-geo'); 104 if (sel) { 105 var opt = sel.querySelector('option[value="geo"]'); 106 if (!opt) { opt = document.createElement('option'); opt.value = 'geo'; sel.appendChild(opt); } 107 opt.textContent = 'â ' + (d.label || ''); 108 sel.value = 'geo'; 109 } 110 setText(card, '.pogoda-city-name', d.label); 111 } else { 112 card.classList.remove('pogoda-is-geo'); 113 card.setAttribute('data-city', String(d.city)); 114 if (sel) { 115 var g = sel.querySelector('option[value="geo"]'); 116 if (g) { g.parentNode.removeChild(g); } 117 sel.value = String(d.city); 118 } 119 setText(card, '.pogoda-city-name', d.label); 120 } 121 dockRefresh(card); 122 } 123 function loadWeather(card, params) { 124 if (!cfg.rest || !window.fetch) { return; } 125 card.classList.add('pogoda-loading'); 126 getJSON(restUrl(cfg.rest, withLang(card, params))) 127 .then(function (d) { if (d && typeof d.ok !== 'undefined' && (d.ok || d.error !== 'rate_limited')) { applyWeather(card, d); } }) 128 .catch(function () { /* залиÑаÑмо ÑеÑвеÑний ÑÐµÐ½Ð´ÐµÑ */ }) 129 .then(function () { card.classList.remove('pogoda-loading'); }); 130 } 131 function storedGeo() { 132 try { var g = JSON.parse(store('local', KEY_GEO) || 'null'); return (g && typeof g.lat === 'number' && typeof g.lon === 'number') ? g : null; } catch (e) { return null; } 133 } 134 function applyGeoToAll(c) { 135 var cards = document.querySelectorAll('.pogoda[data-widget="weather"]'); 136 for (var i = 0; i < cards.length; i++) { 137 if ((cards[i].getAttribute('data-geo') || 'off') !== 'off') { loadWeather(cards[i], { lat: c.lat, lon: c.lon }); } 138 } 139 } 140 function geoRequest(card) { 141 if (!navigator.geolocation || !window.isSecureContext) { return; } 142 card.classList.add('pogoda-geo-busy'); 143 navigator.geolocation.getCurrentPosition(function (p) { 144 var c = { lat: Math.round(p.coords.latitude * 100) / 100, lon: Math.round(p.coords.longitude * 100) / 100 }; 145 store('local', KEY_GEO, JSON.stringify(c)); 146 store('local', KEY_GEO_DENIED, null); 147 card.classList.remove('pogoda-geo-busy'); 148 applyGeoToAll(c); 149 }, function () { 150 store('local', KEY_GEO_DENIED, String(Date.now())); 151 card.classList.remove('pogoda-geo-busy'); 152 }
152, { enableHighAccuracy: false, timeout: 8000, maximumAge: 3600000 }); 153 } 154 function initWeather(card) { 155 var sel = q(card, '.pogoda-city-select'); 156 var idx = card.getAttribute('data-city') || '0'; 157 var geoMode = card.getAttribute('data-geo') || 'off'; 158 var geo = geoMode !== 'off' ? storedGeo() : null; 159 var storedCity = store('local', KEY_CITY); 160 161 if (geo) { 162 loadWeather(card, { lat: geo.lat, lon: geo.lon }); 163 } else if (sel && storedCity !== null && storedCity !== idx && sel.querySelector('option[value="' + storedCity + '"]')) { 164 sel.value = storedCity; 165 loadWeather(card, { city: storedCity }); 166 } else if (isExpired(card)) { 167 loadWeather(card, { city: idx }); 168 } 169 if (geoMode === 'auto' && !geo && storedCity === null) { 170 var denied = parseInt(store('local', KEY_GEO_DENIED), 10) || 0; 171 if (Date.now() - denied > 7 * 864e5) { geoRequest(card); } 172 } 173 if (sel) { 174 sel.addEventListener('change', function () { 175 if (sel.value === 'geo') { 176 var g = storedGeo(); 177 if (g) { loadWeather(card, { lat: g.lat, lon: g.lon }); } 178 return; 179 } 180 store('local', KEY_CITY, sel.value); 181 store('local', KEY_GEO, null); 182 loadWeather(card, { city: sel.value }); 183 }); 184 } 185 var geoBtn = q(card, '.pogoda-geo'); 186 if (geoBtn) { 187 if (!window.isSecureContext || !navigator.geolocation) { geoBtn.hidden = true; } 188 geoBtn.addEventListener('click', function () { geoRequest(card); }); 189 } 190 } 191 192 /* ââ ÐÑÑаÑи воÑога ââ */ 193 function safeUrl(u) { 194 return (typeof u === 'string' && /^https?:\/\//i.test(u)) ? u : ''; 195 } 196 function lossRow(r, withIcon) { 197 var li = document.createElement('li'); 198 li.className = 'pogoda-loss pogoda-loss-' + r.key; 199 if (withIcon && r.icon) { 200 var ic = document.createElement('span'); 201 ic.className = 'pogoda-loss-icon'; 202 ic.innerHTML = r.icon; 203 li.appendChild(ic); 204 } 205 var body = document.createElement('span'); 206 body.className = 'pogoda-loss-body'; 207 var num = document.createElement('span'); 208 num.className = 'pogoda-loss-num'; 209 var total = document.createElement('span'); 210 total.className = 'pogoda-loss-total'; 211 total.textContent = r.total; 212 var inc = document.createElement('em'); 213 inc.className = 'pogoda-loss-inc'; 214 inc.textContent = r.inc || ''; 215 inc.hidden = !r.inc; 216 num.appendChild(total); 217 num.appendChild(document.createTextNode(' ')); 218 num.appendChild(inc); 219 var label = document.createElement('span'); 220 label.className = 'pogoda-loss-label'; 221 label.textContent = r.label; 222 body.appendChild(num); 223 body.appendChild(label); 224 li.appendChild(body); 225 return li; 226 } 227 function applyLosses(card, d) { 228 if (!d || !d.ok) { return; } 229 var rows = d.rows || []; 230 card.classList.toggle('pogoda-stale', !!d.stale); 231 card.setAttribute('data-ts', String(d.fetched_at || 0)); 232 setTitle(card, '.pogoda-losses-title', d.title, d); 233 234 // ÐÐµÐ½Ñ Ð²Ñйни: пÑÐ´Ð¿Ð¸Ñ Ð¿ÑÐ¸Ñ Ð¾Ð´Ð¸ÑÑ Ð³Ð¾Ñовим з ÑеÑвеÑа â ÑнакÑе вÑн 235 // ÑозÑйдеÑÑÑÑ Ð· даÑÐ¾Ñ Ð² Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÑ Ð¿ÑÑÐ»Ñ Ñонового оновленнÑ. 236 var head = q(card, '.pogoda-head'); 237 var dayEl = q(card, '.pogoda-losses-day'); 238 if (!dayEl && head && d.show_day && d.day_label) { 239 dayEl = document.createElement('span'); 240 dayEl.className = 'pogoda-losses-day'; 241 head.insertBefore(dayEl, q(head, '.pogoda-close')); 242 } 243 if (dayEl) { dayEl.textContent = d.day_label || ''; } 244 245 var src = q(card, '.pogoda-losses-source'); 246 if (src && safeUrl(d.source_url)) { src.setAttribute('href', safeUrl(d.source_url)); } 247 248 if (!rows.length) { return; } 249 // ÐлаÑка могла вÑдÑендеÑиÑиÑÑ Ð±ÐµÐ· Ð´Ð°Ð½Ð¸Ñ (джеÑело лежало Ñи 250 // ÑÑоÑÑнка з кеÑÑ) â ÑÐ¾Ð´Ñ ÑпиÑок бÑдÑÑмо з вÑдповÑÐ´Ñ REST. 251 var list = q(card, '.pogoda-losses-list'); 252 if (!list) { 253 list = document.createElement('ul');
254 list.className = 'pogoda-losses-list'; 255 var empty = q(card, '.pogoda-losses-empty'); 256 if (empty) { empty.parentNode.replaceChild(list, empty); } 257 else { card.insertBefore(list, q(card, '.pogoda-foot')); } 258 } 259 rows.forEach(function (r) { 260 var li = q(list, '.pogoda-loss-' + r.key); 261 if (!li) { list.appendChild(lossRow(r, !!d.show_icons)); return; } 262 setText(li, '.pogoda-loss-total', r.total); 263 var inc = q(li, '.pogoda-loss-inc'); 264 if (inc) { inc.textContent = r.inc || ''; inc.hidden = !r.inc; } 265 }); 266 card.classList.remove('pogoda-unavailable'); 267 } 268 function initLosses(card) { 269 if (!cfg.losses || !window.fetch || !isExpired(card)) { return; } 270 getJSON(restUrl(cfg.losses, withLang(card, { items: card.getAttribute('data-items') || '' }))) 271 .then(function (d) { applyLosses(card, d); }) 272 .catch(function () {}); 273 } 274 275 /* ââ ÐаÑÑа ââ */ 276 function initMap(card) { 277 var btn = q(card, '.pogoda-map-load'); 278 if (!btn) { return; } 279 btn.addEventListener('click', function () { 280 var f = document.createElement('iframe'); 281 f.src = btn.getAttribute('data-src'); 282 f.title = 'DeepStateMap'; 283 f.setAttribute('allowfullscreen', ''); 284 f.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin'); 285 btn.parentNode.replaceChild(f, btn); 286 card.classList.remove('pogoda-map-click'); 287 card.classList.add('pogoda-map-eager'); 288 }); 289 } 290 291 /* ââ ÐÑоÑÑ: кÑÑÑ Ð²Ð°Ð»ÑÑ, меÑали, конвеÑÑÐµÑ ââ */ 292 function parseJSONAttr(el, attr) { 293 try { return JSON.parse(el.getAttribute(attr) || '{}') || {}; } catch (e) { return {}; } 294 } 295 /* Те Ñаме ÑоÑмаÑÑваннÑ, Ñо й на ÑеÑвеÑÑ (pogoda_fmt_num): ÑнакÑе пÑÑÐ»Ñ 296 пеÑÑого наÑиÑÐºÐ°Ð½Ð½Ñ ÐºÐ»Ð°Ð²ÑÑÑ ÑиÑло «ÑÑÑибаÑ» в ÑнÑий виглÑд. */ 297 function fmtNum(value, dec, decSep, thousands) { 298 var neg = value < 0; 299 var parts = Math.abs(value).toFixed(dec).split('.'); 300 parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousands || ''); 301 return (neg ? 'â' : '') + parts.join(decSep || ','); 302 } 303 /* Як pogoda_money_scale(): дÑÑÐ±Ð½Ñ ÐºÑÑÑи коÑиÑÑÑмо за 10/100/1000 одиниÑÑ, 304 а кÑÑÑ Ð±Ð»Ð¸Ð·Ñко одиниÑÑ Ð»Ð¸ÑаÑмо Ñк Ñ â «1 USD = 0,86 â¬Â» ÑиÑаÑÑÑÑÑ ÐºÑаÑе, 305 нÑж «10 USD = 8,62 â¬Â». */ 306 function scaleMult(rate) { 307 if (!(rate > 0) || rate >= 0.2) { return 1; } 308 var steps = [10, 100, 1000]; 309 var m = 1; 310 for (var i = 0; i < steps.length; i++) { m = steps[i]; if (rate * m >= 1) { break; } } 311 return m; 312 } 313 function rateDecimals(v) { 314 v = Math.abs(v); 315 if (v >= 1000) { return 0; } 316 return v >= 1 ? 2 : 4; 317 } 318 function setDir(el, prefix, dir) { 319 el.classList.remove(prefix + 'up', prefix + 'down'); 320 if (dir) { el.classList.add(prefix + dir); } 321 } 322 323 function ratesRow(r) { 324 var li = document.createElement('li'); 325 li.className = 'pogoda-rate pogoda-rate-' + String(r.code).toLowerCase() + (r.dir ? ' pogoda-rate-' + r.dir : ''); 326 if (r.title) { li.title = r.title; } 327 var cur = document.createElement('span'); 328 cur.className = 'pogoda-rate-cur'; 329 if (r.flag) { 330 var fl = document.createElement('span'); 331 fl.className = 'pogoda-rate-flag'; 332 fl.setAttribute('aria-hidden', 'true'); 333 fl.textContent = r.flag; 334 cur.appendChild(fl); 335 } 336 var code = document.createElement('span'); 337 code.className = 'pogoda-rate-code'; 338 code.textContent = r.unit; 339 cur.appendChild(code); 340 var vals = document.createElement('span'); 341 vals.className = 'pogoda-rate-vals'; 342 if (r.buy) { 343 var b = document.createElement('span'); 344 b.className = 'pogoda-rate-buy'; 345 b.textContent = r.buy; 346 var sl = document.createElement('span'); 347 sl.className = 'pogoda-rate-sell'; 348 sl.textContent = r.sell; 349 vals.appendChild(b); 350 vals.appendChild(sl); 351 } else { 352 var v = document.createElement('span'); 353 v.className = 'pogoda-rate-value';
354 v.textContent = r.value; 355 vals.appendChild(v); 356 } 357 var d = document.createElement('em'); 358 d.className = 'pogoda-rate-delta'; 359 d.textContent = r.delta || ''; 360 d.hidden = !r.delta; 361 li.appendChild(cur); 362 li.appendChild(vals); 363 li.appendChild(d); 364 return li; 365 } 366 function ensureList(card, cls, emptyCls) { 367 var list = q(card, '.' + cls); 368 if (list) { return list; } 369 list = document.createElement('ul'); 370 list.className = cls; 371 var empty = q(card, '.' + emptyCls); 372 if (empty) { empty.parentNode.replaceChild(list, empty); } 373 else { card.insertBefore(list, q(card, '.pogoda-foot')); } 374 return list; 375 } 376 function applyRates(card, d) { 377 if (!d || !d.ok || !d.rows || !d.rows.length) { return; } 378 card.classList.toggle('pogoda-stale', !!d.stale); 379 card.classList.remove('pogoda-unavailable'); 380 card.setAttribute('data-ts', String(d.fetched_at || 0)); 381 setTitle(card, '.pogoda-rates-title', d.title, d); 382 var src = q(card, '.pogoda-rates-source'); 383 if (src) { 384 if (d.source) { src.textContent = d.source; } 385 if (safeUrl(d.source_url)) { src.setAttribute('href', safeUrl(d.source_url)); } 386 } 387 var list = ensureList(card, 'pogoda-rates-list', 'pogoda-rates-empty'); 388 d.rows.forEach(function (r) { 389 var li = q(list, '.pogoda-rate-' + String(r.code).toLowerCase()); 390 if (!li) { list.appendChild(ratesRow(r)); return; } 391 setDir(li, 'pogoda-rate-', r.dir); 392 setText(li, '.pogoda-rate-code', r.unit); 393 if (r.buy) { 394 setText(li, '.pogoda-rate-buy', r.buy); 395 setText(li, '.pogoda-rate-sell', r.sell); 396 } else { 397 setText(li, '.pogoda-rate-value', r.value); 398 } 399 var dl = q(li, '.pogoda-rate-delta'); 400 if (dl) { dl.textContent = r.delta || ''; dl.hidden = !r.delta; } 401 }); 402 dockRefresh(card); 403 } 404 function initRates(card) { 405 if (!cfg.rates || !window.fetch || !isExpired(card)) { return; } 406 getJSON(restUrl(cfg.rates, withLang(card, { items: card.getAttribute('data-items') || '', base: card.getAttribute('data-base') || '' }))) 407 .then(function (d) { applyRates(card, d); }) 408 .catch(function () {}); 409 } 410 411 function metalsRow(r) { 412 var li = document.createElement('li'); 413 li.className = 'pogoda-metal pogoda-metal-' + String(r.code).toLowerCase() + (r.dir ? ' pogoda-metal-' + r.dir : ''); 414 if (r.title) { li.title = r.title; } 415 var name = document.createElement('span'); 416 name.className = 'pogoda-metal-name'; 417 if (r.icon) { 418 var ic = document.createElement('span'); 419 ic.className = 'pogoda-metal-icon'; 420 ic.innerHTML = r.icon; 421 name.appendChild(ic); 422 } 423 var lb = document.createElement('span'); 424 lb.className = 'pogoda-metal-label'; 425 lb.textContent = r.label; 426 name.appendChild(lb); 427 var vals = document.createElement('span'); 428 vals.className = 'pogoda-metal-vals'; 429 var price = document.createElement('span'); 430 price.className = 'pogoda-metal-price'; 431 price.textContent = r.price + ' '; 432 var cur = document.createElement('span'); 433 cur.className = 'pogoda-metal-cur'; 434 cur.textContent = r.cur; 435 price.appendChild(cur); 436 vals.appendChild(price); 437 if (r.unit) { 438 var u = document.createElement('span'); 439 u.className = 'pogoda-metal-unit'; 440 u.textContent = '/ ' + r.unit; 441 vals.appendChild(u); 442 } 443 var d = document.createElement('em'); 444 d.className = 'pogoda-metal-delta'; 445 d.textContent = r.delta || ''; 446 d.hidden = !r.delta; 447 li.appendChild(name); 448 li.appendChild(vals); 449 li.appendChild(d); 450 return li; 451 } 452 function applyMetals(card, d) { 453 if (!d || !d.ok || !d.rows || !d.rows.length) { return; } 454 card.classList.toggle('pogoda-stale', !!d.stale); 455 card.classList.remove('pogoda-unavailable'); 456 card.setAttribute('data-ts', String(d.fetched_at || 0)); 457 setTitle(card, '.pogoda-metals-title', d.title, d); 458 var src = q(card, '.pogoda-metals-source'); 459 if (src && safeUrl(d.source_url)) { src.setAttribute('href', safeUrl(d.source_url)); } 460 var list = ensureList(card, 'pogoda-metals-list', 'pogoda-metals-empty'); 461 d.rows.forEach(function (r) { 462 var li = q(list, '.pogoda-metal-' + String(r.code).toLowerCase()); 463 if (!li) { list.appendChild(metalsRow(r)); return; } 464 setDir(li, 'pogoda-metal-', r.dir); 465 var price = q(li, '.pogoda-metal-price'); 466 if (price) { 467 var cur = q(price, '.pogoda-metal-cur'); 468 price.textContent = r.price + ' '; 469 if (cur) { cur.textContent = r.cur; price.appendChild(cur); } 470 } 471 var dl = q(li, '.pogoda-metal-delta'); 472 if (dl) { dl.textContent = r.delta || ''; dl.hidden = !r.delta; } 473 }); 474 dockRefresh(card); 475 } 476 function initMetals(card) { 477 if (!cfg.metals || !window.fetch || !isExpired(card)) { return; } 478 getJSON(restUrl(cfg.metals, withLang(card, { items: card.getAttribute('data-items') || '', unit: card.getAttribute('data-unit') || '' }))) 479 .then(function (d) { applyMetals(card, d); }) 480 .catch(function () {}); 481 } 482 483 function initConverter(card) { 484 var amountEl = q(card, '.pogoda-conv-amount'); 485 var fromEl = q(card, '.pogoda-conv-from'); 486 var toEl = q(card, '.pogoda-conv-to'); 487 var outEl = q(card, '.pogoda-conv-result'); 488 if (!amountEl || !fromEl || !toEl || !outEl) { return; } 489 var rateEl = q(card, '.pogoda-conv-rate'); 490 var swapEl = q(card, '.pogoda-conv-swap'); 491 var decSep = card.getAttribute('data-dec-sep') || ','; 492 var thousands = card.getAttribute('data-thousands') || ''; 493 var rates = parseJSONAttr(card, 'data-rates'); 494 var syms = parseJSONAttr(card, 'data-sym'); 495 var decs = parseJSONAttr(card, 'data-dec'); 496 497 function parseAmount(txt) { 498 txt = String(txt == null ? '' : txt); 499 if (thousands) { txt = txt.split(thousands).join(''); } 500 txt = txt.replace(/[\s ââ¯]/g, '').replace(/,/g, '.').replace(/[^0-9.]/g, ''); 501 var dot = txt.indexOf('.'); 502 if (dot > -1) { txt = txt.slice(0, dot + 1) + txt.slice(dot + 1).replace(/\./g, ''); } 503 var v = parseFloat(txt); 504 return isFinite(v) && v >= 0 ? v : 0; 505 } 506 function decFor(code, value) { 507 var d = (typeof decs[code] === 'number') ? decs[code] : 2; 508 if (Math.abs(value) < 1 && d < 4) { d = 4; } 509 return d; 510 } 511 function recalc() { 512 var from = fromEl.value; 513 var to = toEl.value; 514 var rf = rates[from]; 515 var rt = rates[to]; 516 if (!rf || !rt) { outEl.textContent = 'â'; if (rateEl) { rateEl.hidden = true; } return; } 517 var res = parseAmount(amountEl.value) * rf / rt; 518 outEl.textContent = fmtNum(res, decFor(to, res), decSep, thousands); 519 if (rateEl) { 520 var one = rf / rt; 521 var m = scaleMult(one); 522 rateEl.textContent = (m > 1 ? fmtNum(m, 0, decSep, thousands) : '1') + ' ' + from + ' = ' 523 + fmtNum(one * m, rateDecimals(one * m), decSep, thousands) + ' ' + (syms[to] || to); 524 rateEl.hidden = false;
525 } 526 } 527 amountEl.addEventListener('input', recalc); 528 fromEl.addEventListener('change', recalc); 529 toEl.addEventListener('change', recalc); 530 if (swapEl) { 531 swapEl.addEventListener('click', function () { 532 var t = fromEl.value; 533 fromEl.value = toEl.value; 534 toEl.value = t; 535 recalc(); 536 }); 537 } 538 if (cfg.rates && window.fetch && isExpired(card)) { 539 getJSON(restUrl(cfg.rates, withLang(card, { w: 'converter', items: card.getAttribute('data-items') || '', base: card.getAttribute('data-base') || '' }))) 540 .then(function (d) { 541 if (!d || !d.ok || !d.map) { return; } 542 for (var k in d.map) { 543 if (Object.prototype.hasOwnProperty.call(d.map, k)) { rates[k] = d.map[k]; } 544 } 545 card.setAttribute('data-ts', String(d.fetched_at || 0)); 546 card.classList.toggle('pogoda-stale', !!d.stale); 547 if (d.title) { setTitle(card, '.pogoda-converter-title', d.title, d); } 548 recalc(); 549 }) 550 .catch(function () {}); 551 } 552 } 553 554 /* ââ ÐалÑкÑлÑÑоÑи ââââââââââââââââââââââââââââââââââââââââââââââââââââââ 555 Ð¢Ñ ÑÐ°Ð¼Ñ ÑоÑмÑли, Ñо в includes/calc.php (pogoda_calc_compute): ÑеÑÐ²ÐµÑ 556 малÑÑ Ð¿ÐµÑÑий ÑезÑлÑÑаÑ, бÑаÑÐ·ÐµÑ Ð¿ÐµÑеÑÐ°Ñ Ð¾Ð²ÑÑ Ð¿Ñд ÑÐ°Ñ Ð½Ð°Ð±Ð¾ÑÑ. ЯкÑо ÑÑÑ 557 ÑоÑÑ Ð¼ÑнÑÑÑÑÑÑ â мÑнÑÑи Ñ Ñам, ÑнакÑе пеÑÑе ÑиÑло «ÑÑÑибне». */ 558 function calcRun(kind, v, ctx) { 559 var out = {}; 560 var money = function (x, dec) { return fmtNum(x, dec === undefined ? 2 : dec, ctx.sep, ctx.tho) + ' ' + ctx.cur; }; 561 var n = function (name) { return parseFloat(String(v[name] === undefined ? 0 : v[name]).replace(',', '.')) || 0; }; 562 var u = function (key) { return ctx.units[key] || ''; }; 563 var sum, rate, term, i, pay, total, income, tax, net, vat, gross, liters, cost, area, one, pieces, vol; 564 565 switch (kind) { 566 case 'loan': 567 sum = Math.max(0, n('sum')); rate = Math.max(0, n('rate')); term = Math.max(1, Math.round(n('term'))); 568 i = rate / 1200; 569 pay = i > 0 ? sum * i / (1 - Math.pow(1 + i, -term)) : sum / term; 570 out.payment = money(pay); out.total = money(pay * term); out.overpay = money(pay * term - sum); 571 break; 572 case 'deposit': 573 sum = Math.max(0, n('sum')); rate = Math.max(0, n('rate')); term = Math.max(1, Math.round(n('term'))); 574 total = (v.cap === 'none') ? sum * (1 + rate / 100 * term / 12) : sum * Math.pow(1 + rate / 1200, term); 575 income = total - sum; tax = income * 0.23; 576 out.income = money(income); out.total = money(sum + income - tax); out.tax = money(tax); 577 break; 578 case 'vat': 579 sum = Math.max(0, n('sum')); rate = Math.max(0, n('rate')); 580 if (v.mode === 'extract') { net = sum / (1 + rate / 100); vat = sum - net; gross = sum; } 581 else { net = sum; vat = sum * rate / 100; gross = sum + vat; } 582 out.vat = money(vat); out.net = money(net); out.gross = money(gross); 583 break; 584 case 'fuel': 585 liters = Math.max(0, n('distance')) * Math.max(0, n('rate')) / 100; 586 cost = liters * Math.max(0, n('price')); 587 out.liters = fmtNum(liters, 1, ctx.sep, ctx.tho) + ' ' + u('l'); 588 out.cost = money(cost); 589 out.per_person = money(cost / Math.max(1, Math.round(n('people')))); 590 break; 591 case 'customs': { 592 var price = Math.max(0, n('price')); 593 var engine = Math.max(0, n('engine')); 594 var age = Math.max(1, Math.min(15, new Date().getFullYear() - (n('year') > 1900 ? n('year') : new Date().getFullYear()))); 595 var excise; 596 if (v.fuel === 'electro') { excise = 60; } 597 else if (v.fuel === 'hybrid') { excise = 100; } 598 else { 599 var baseRate = (v.fuel === 'diesel') ? (engine <= 3500 ? 75 : 150) : (engine <= 3000 ? 50 : 100); 600 excise = baseRate * (engine / 1000) * age; 601 } 602 var duty = (v.origin === 'eu') ? 0 : price * 0.10; 603 var cvat = (price + duty + excise) * 0.20; 604 var ctotal = duty + excise + cvat; 605 var eur = function (x) { return fmtNum(x, 0, ctx.sep, ctx.tho) + ' â¬'; }; 606 out.duty = eur(duty); out.excise = eur(excise); out.vat = eur(cvat); out.total = eur(ctotal); 607 if (ctx.eur > 0) { out.total_local = money(ctotal * ctx.eur, 0); } 608 break; 609 } 610 case 'bmi': { 611 var h = Math.max(0.5, n('height') / 100); 612 var w = Math.max(1, n('weight')); 613 var bmi = w / (h * h); 614 var cat = bmi < 18.5 ? 0 : (bmi < 25 ? 1 : (bmi < 30 ? 2 : (bmi < 35 ? 3 : (bmi < 40 ? 4 : 5)))); 615 out.bmi = fmtNum(bmi, 1, ctx.sep, ctx.tho); 616 out.category = (ctx.cats && ctx.cats[cat]) || ''; 617 out.normal = fmtNum(18.5 * h * h, 1, ctx.sep, ctx.tho) + 'â' + fmtNum(24.9 * h * h, 1, ctx.sep, ctx.tho) + ' ' + u('kg'); 618 break; 619 } 620 case 'calories': { 621 var bmr = 10 * Math.max(1, n('weight')) + 6.25 * Math.max(1, n('height')) - 5 * Math.max(1, n('age')) + (v.sex === 'f' ? -161 : 5); 622 var k = { none: 1.2, low: 1.375, mid: 1.55, high: 1.725, max: 1.9 }; 623 var norm = bmr * (k[v.activity] || 1.375); 624 out.bmr = fmtNum(bmr, 0, ctx.sep, ctx.tho) + ' ' + u('kcal'); 625 out.norm = fmtNum(norm, 0, ctx.sep, ctx.tho) + ' ' + u('kcal'); 626 out.loss = fmtNum(norm * 0.85, 0, ctx.sep, ctx.tho) + ' ' + u('kcal'); 627 break; 628 } 629 case 'tile': 630 area = Math.max(0, n('length')) * Math.max(0, n('width')); 631 one = (Math.max(1, n('tile_w')) / 100) * (Math.max(1, n('tile_h')) / 100); 632 pieces = one > 0 ? Math.ceil(area * (1 + Math.max(0, n('spare')) / 100) / one) : 0; 633 out.area = fmtNum(area, 2, ctx.sep, ctx.tho) + ' ' + u('m2'); 634 out.pieces = fmtNum(pieces, 0, ctx.sep, ctx.tho) + ' ' + u('pcs'); 635 out.area_total = fmtNum(pieces * one, 2, ctx.sep, ctx.tho) + ' ' + u('m2'); 636 break; 637 case 'concrete': { 638 vol = Math.max(0, n('length')) * Math.max(0, n('width')) * Math.max(0, n('height')); 639 var mix = { m100: [210, 870, 1080], m200: [280, 800, 1080], m300: [380, 705, 1080] }; 640 var m = mix[v.grade] || mix.m200; 641 out.volume = fmtNum(vol, 2, ctx.sep, ctx.tho) + ' ' + u('m3'); 642 out.cement = fmtNum(vol * m[0], 0, ctx.sep, ctx.tho) + ' ' + u('kg'); 643 out.sand = fmtNum(vol * m[1], 0, ctx.sep, ctx.tho) + ' ' + u('kg'); 644 out.gravel = fmtNum(vol * m[2], 0, ctx.sep, ctx.tho) + ' ' + u('kg'); 645 break; 646 } 647 case 'pregnancy': { 648 var cycle = Math.max(20, Math.min(45, Math.round(n('cycle') || 28))); 649 var ms = Date.parse((v.lmp || '') + 'T12:00:00Z'); 650 if (isNaN(ms)) { ms = Date.now() - 56 * 864e5; } 651 var due = ms + (280 + (cycle - 28)) * 864e5; 652 var days = Math.floor((Date.now() - ms) / 864e5); 653 var d = new Date(due); 654 var pad = function (x) { return (x < 10 ? '0' : '') + x; }; 655 out.due = pad(d.getUTCDate()) + '.' + pad(d.getUTCMonth() + 1) + '.' + d.getUTCFullYear(); 656 out.week = Math.max(0, Math.min(45, Math.floor(days / 7))) + ' ' + u('weeks'); 657 out.left = Math.max(0, Math.ceil((due - Date.now()) / 864e5)) + ' ' + u('days'); 658 break; 659 } 660 } 661 return out; 662 } 663 664 function initCalc(card) { 665 var kind = card.getAttribute('data-kind') || ''; 666 var inputs = card.querySelectorAll('.pogoda-calc-in'); 667 if (!inputs.length) { return; } 668 var ctx = { 669 sep: card.getAttribute('data-dec-sep') || ',', 670 tho: card.getAttribute('data-thousands') || '', 671 cur: card.getAttribute('data-cur') || '', 672 units: parseJSONAttr(card, 'data-units'), 673 cats: (function () { try { return JSON.parse(card.getAttribute('data-cats') || '[]'); } catch (e) { return []; } })(), 674 eur: parseFloat(card.getAttribute('data-eur') || '0') || 0 675 }; 676 var initial = []; 677 for (var i = 0; i < inputs.length; i++) { initial.push(inputs[i].value); } 678 679 function values() { 680 var v = {}; 681 for (var j = 0; j < inputs.length; j++) {
682 v[inputs[j].getAttribute('data-name')] = inputs[j].value; 683 } 684 return v; 685 } 686 function recalc() { 687 var res = calcRun(kind, values(), ctx); 688 for (var key in res) { 689 if (!Object.prototype.hasOwnProperty.call(res, key)) { continue; } 690 var row = card.querySelector('.pogoda-calc-row[data-key="' + key + '"] .pogoda-calc-rval'); 691 if (row) { row.textContent = res[key]; } 692 } 693 } 694 for (var k = 0; k < inputs.length; k++) { 695 inputs[k].addEventListener('input', recalc); 696 inputs[k].addEventListener('change', recalc); 697 } 698 var reset = q(card, '.pogoda-calc-reset'); 699 if (reset) { 700 reset.addEventListener('click', function () { 701 for (var r = 0; r < inputs.length; r++) { inputs[r].value = initial[r]; } 702 recalc(); 703 }); 704 } 705 } 706 707 /* ââ ÐаÑÑнеÑÑÑка каÑÑка: пеÑевÑÑка за VIN ââ */ 708 function initPartner(card) { 709 var form = q(card, '.pogoda-partner-vin'); 710 if (!form) { return; } 711 var input = q(form, '.pogoda-partner-vin-input'); 712 if (!input) { return; } 713 form.addEventListener('submit', function (e) { 714 var vin = (input.value || '').replace(/[^A-Za-z0-9]/g, '').toUpperCase(); 715 var tpl = input.getAttribute('data-url') || ''; 716 if (!vin) { e.preventDefault(); input.focus(); return; } 717 // Шаблон Ñз {vin} веде ÑоÑно на ÑÑоÑÑÐ½ÐºÑ Ð¿ÐµÑевÑÑки з наÑим кодом; 718 // без нÑого лиÑаÑмо звиÑÐ°Ð¹Ð½Ñ Ð²ÑдпÑÐ°Ð²ÐºÑ ÑоÑми (вона Ñеж Ñз кодом). 719 if (tpl.indexOf('%7Bvin%7D') > -1 || tpl.indexOf('{vin}') > -1) { 720 e.preventDefault(); 721 var url = tpl.split('%7Bvin%7D').join(encodeURIComponent(vin)).split('{vin}').join(encodeURIComponent(vin)); 722 window.open(url, '_blank', 'noopener'); 723 } 724 }); 725 input.addEventListener('input', function () { 726 var v = (input.value || '').replace(/[^A-Za-z0-9]/g, '').toUpperCase(); 727 if (v !== input.value) { input.value = v; } 728 }); 729 } 730 731 /* ââ ÐакÑиÑÑÑ Ð¿Ð»Ð°Ð²Ð°ÑÑÐ¸Ñ ââ */ 732 function removeCard(card) { 733 var wrap = card.parentNode; 734 if (!wrap) { return; } 735 wrap.removeChild(card); 736 if (!wrap.classList || !wrap.classList.contains('pogoda-floating-wrap')) { return; } 737 // Разом Ñз плаÑÐºÐ¾Ñ Ð·Ð½Ð¸ÐºÐ°Ñ Ñ ÑÑ Ð²ÐºÐ»Ð°Ð´ÐºÐ° в Ð´Ð¾ÐºÑ (ÑелеÑон пÑÑÐ»Ñ Ð¿Ð¾Ð²Ð¾ÑоÑÑ). 738 var tab = wrap.querySelector('.pogoda-dock-tab[data-for="' + (card.getAttribute('data-widget') || '') + '"]'); 739 if (tab && tab.parentNode) { tab.parentNode.removeChild(tab); } 740 if (!wrap.querySelector('.pogoda') && wrap.parentNode) { 741 wrap.parentNode.removeChild(wrap); 742 } 743 } 744 /* ÐÑев'Ñ Ð°Ð´Ð¼ÑнÑÑÑÑаÑоÑа (?pogoda_preview): «закÑиÑо до кÑнÑÑ ÑеÑÑÑ» не 745 ÑиÑаÑмо й не пиÑемо, ÑнакÑе один доÑик â Ñ Ð¾Ð²Ð°Ð² би плаÑки з ÑÑÑÑ 746 наÑÑÑÐ¿Ð½Ð¸Ñ Ð¿Ñев'Ñ Ð² ÑÑй вкладÑÑ Ð±ÑаÑзеÑа. */ 747 function isPreviewWrap(wrap) { 748 return !!(wrap && wrap.getAttribute && wrap.getAttribute('data-preview') === '1'); 749 } 750 function initClose(card) { 751 var close = q(card, '.pogoda-close'); 752 if (!close) { return; } 753 var id = card.getAttribute('data-widget') || 'w'; 754 close.addEventListener('click', function () { 755 var wrap = card.parentNode; 756 // У Ð´Ð¾ÐºÑ Ð½Ð° ÑелеÑÐ¾Ð½Ñ â лиÑе згоÑÑÐ°Ñ Ð¿Ð»Ð°ÑÐºÑ Ð½Ð°Ð·Ð°Ð´ Ñ Ð²ÐºÐ»Ð°Ð´ÐºÑ: ÑÑ Ð¾Ð²Ð°Ñи 757 // вÑе â окÑема кнопка в ÑÑÐ´ÐºÑ Ð²ÐºÐ»Ð°Ð´Ð¾Ðº. 758 if (wrap && wrap.classList && wrap.classList.contains('pogoda-dock') && dockMobile()) { 759 dockOpen(wrap, null); 760 return; 761 } 762 removeCard(card); 763 if (!isPreviewWrap(wrap)) { store('session', 'pogoda_closed_' + id, '1'); } 764 }); 765 } 766 767 /* ââ ÐобÑлÑний док плаваÑÑÐ¸Ñ Ð¿Ð»Ð°Ñок ââ 768 РозмÑÑÐºÑ Ð²ÐºÐ»Ð°Ð´Ð¾Ðº дÑÑкÑÑ PHP (pogoda_dock_bar); CSS показÑÑ ÑÑ Ð»Ð¸Ñе на 769 екÑÐ°Ð½Ñ â¤1023px Ñ Ð»Ð¸Ñе з клаÑом .pogoda-dock на обгоÑÑÑÑ â його ÑÑавимо 770 ÑÑÑ, Ñож без ÑкÑипÑа плаÑки видно Ñк ÑанÑÑе. */ 771 var DOCK_MQ = '(max-width: 1023px)'; // Ñе Ñаме, Ñо @media Ñ pogoda.css 772 function dockMobile() { 773 return !!(window.matchMedia && window.matchMedia(DOCK_MQ).matches); 774 } 775 /* Ðиве ÑиÑло Ð´Ð»Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ¸: ÑемпеÑаÑÑÑа, кÑÑÑ, ÑÐ½Ð´ÐµÐºÑ Ð¿Ð¾Ð²ÑÑÑÑ⦠ÐовÑе за 12 776 ÑимволÑв Ñ Ð²ÐºÐ»Ð°Ð´ÐºÑ Ð½Ðµ лÑзе â ÑÐ¾Ð´Ñ Ð»Ð¸ÑаÑÑÑÑÑ Ñама назва. ÐÑогноз â з 777 пÑеÑÑкÑом «до» (data-prefix з i18n), Ñоб не ÑиÑавÑÑ Ñк поÑоÑна. */ 778 function dockValue(card, tab) { 779 if (card.classList.contains('pogoda-unavailable')) { return ''; } 780 var t = function (sel) { 781 var n = q(card, sel); 782 return n ? (n.textContent || '').replace(/\s+/g, ' ').trim() : ''; 783 }; 784 var v = ''; 785 switch (card.getAttribute('data-widget')) {
786 case 'weather': v = t('.pogoda-temp'); break; 787 case 'forecast': 788 v = t('.pogoda-fday-max'); 789 if (v && v !== 'â' && tab && tab.getAttribute('data-prefix')) { v = tab.getAttribute('data-prefix') + ' ' + v; } 790 break; 791 case 'rates': v = (t('.pogoda-rate-code') + ' ' + (t('.pogoda-rate-value') || t('.pogoda-rate-sell'))).trim(); break; 792 case 'metals': v = t('.pogoda-metal-price'); break; 793 case 'air': v = t('.pogoda-air-aqi'); break; 794 case 'sun': v = t('.pogoda-sun-val'); break; 795 } 796 if (v === 'â' || v.length > 12) { v = ''; } 797 return v; 798 } 799 /* Ðогода («+9°»), пÑогноз («до +19°») Ñ ÐºÑÑÑ («USD 44,62») ÑпÑзнаÑÑÑÑÑ Ð· 800 Ñамого ÑиÑла, Ñож Ñ Ð½Ð¸Ñ ÑиÑло замÑнÑÑ Ð½Ð°Ð·Ð²Ñ â ÑнакÑе ÑÑи вкладки не 801 лÑзÑÑÑ Ñ 375px. */ 802 var DOCK_BRIEF = { weather: 1, forecast: 1, rates: 1 }; 803 /* Ðконка вкладки погоди/пÑÐ¾Ð³Ð½Ð¾Ð·Ñ â жива, з ÑÐ°Ð¼Ð¾Ñ Ð¿Ð»Ð°Ñки (ÑÑан неба на 804 ÑÑогоднÑ), а не ÑÑаÑиÑна Ñ Ð¼Ð°Ñка, Ñка на доÑÑ Ð±ÑеÑе. */ 805 function dockIcon(card, tab) { 806 var id = card.getAttribute('data-widget'); 807 var src = id === 'weather' ? q(card, '.pogoda-main-icon-wrap svg') : (id === 'forecast' ? q(card, '.pogoda-fday-icon svg') : null); 808 var cur = q(tab, '.pogoda-dock-icon'); 809 if (!src || !cur || !src.cloneNode) { return; } 810 var icon = src.cloneNode(true); 811 var cls = (icon.getAttribute('class') || '').replace(/\bpogoda-main-icon\b/, '').replace(/\s+/g, ' ').trim(); 812 icon.setAttribute('class', cls + ' pogoda-dock-icon'); 813 cur.parentNode.replaceChild(icon, cur); 814 } 815 function dockRefresh(card) { 816 var wrap = card.parentNode; 817 if (!wrap || !wrap.classList || !wrap.classList.contains('pogoda-floating-wrap')) { return; } 818 var id = card.getAttribute('data-widget') || ''; 819 var tab = wrap.querySelector('.pogoda-dock-tab[data-for="' + id + '"]'); 820 var val = tab ? q(tab, '.pogoda-dock-val') : null; 821 if (!tab || !val) { return; } 822 var v = dockValue(card, tab); 823 val.textContent = v; 824 var label = q(tab, '.pogoda-dock-label'); 825 var brief = !!(v && DOCK_BRIEF[id]); 826 tab.classList.toggle('pogoda-dock-brief', brief); 827 if (label) { tab.setAttribute('aria-label', (label.textContent || '') + (v ? ' ' + v : '')); } 828 dockIcon(card, tab); 829 } 830 /* ÐÑдкÑиÑи плаÑÐºÑ id (null â згоÑнÑÑи вÑÑ). ÐдноÑаÑно вÑдкÑиÑа лиÑе одна. */ 831 function dockOpen(wrap, id) { 832 var cards = wrap.querySelectorAll('.pogoda'); 833 var tabs = wrap.querySelectorAll('.pogoda-dock-tab'); 834 var open = null; 835 var was = wrap.getAttribute('data-dock-open') || ''; 836 var active = document.activeElement; 837 for (var i = 0; i < cards.length; i++) { 838 var on = id !== null && cards[i].getAttribute('data-widget') === id; 839 cards[i].classList.toggle('pogoda-dock-active', on); 840 if (on) { open = cards[i]; } 841 } 842 var focusTab = null; 843 for (var j = 0; j < tabs.length; j++) { 844 var mine = id !== null && tabs[j].getAttribute('data-for') === id; 845 tabs[j].setAttribute('aria-expanded', mine ? 'true' : 'false'); 846 if (!open && was && tabs[j].getAttribute('data-for') === was) { focusTab = tabs[j]; } 847 } 848 wrap.classList.toggle('pogoda-dock-open', !!open); 849 if (open) { 850 wrap.setAttribute('data-dock-open', id); 851 open.scrollTop = 0; 852 } else { 853 wrap.removeAttribute('data-dock-open'); 854 // ФокÑÑ Ð±Ñв Ñ Ð·Ð³Ð¾ÑнÑÑÑй плаÑÑÑ (â, Escape з клавÑаÑÑÑи) â повеÑÑаÑмо 855 // на ÑÑ Ð²ÐºÐ»Ð°Ð´ÐºÑ, ÑнакÑе вÑн Ð¿Ð°Ð´Ð°Ñ Ð½Ð° <body> Ñ Tab поÑÐ¸Ð½Ð°Ñ Ð· поÑаÑкÑ. 856 if (focusTab && (!active || active === document.body || !document.body.contains(active) || !wrap.contains(active) || (active.closest && active.closest('.pogoda')))) { 857 try { focusTab.focus(); } catch (e) { /* ignore */ } 858 } 859 } 860 } 861 function initDock(wrap) { 862 var bar = q(wrap, '.pogoda-dock-bar'); 863 if (!bar) { return; } 864 // РозмÑÑка нова, а CSS ÑÑаÑий (кеÑ/CDN без ?ver): Ð¿Ð°Ð½ÐµÐ»Ñ Ð½Ðµ ÑÑилÑзована 865 // (display: block замÑÑÑÑ none/flex) â Ñ Ð¾Ð²Ð°Ñмо ÑÑ Ñ Ð»Ð¸ÑаÑмо ÑÑÐ¾Ñ Ñк бÑв, 866 // ÑнакÑе â плаÑки на ÑелеÑÐ¾Ð½Ñ ÑÑав би поÑожнÑÐ¾Ñ Ð´ÑÑÑ. 867 var disp = window.getComputedStyle ? getComputedStyle(bar).display : 'none'; 868 if (disp !== 'none' && disp !== 'flex') { 869 bar.style.display = 'none'; 870 return; 871 } 872 if (!isPreviewWrap(wrap) && store('session', 'pogoda_dock_closed') === '1') { 873 if (wrap.parentNode) { wrap.parentNode.removeChild(wrap); } 874 return; 875 } 876 wrap.classList.add('pogoda-dock'); 877 var cards = wrap.querySelectorAll('.pogoda'); 878 for (var i = 0; i < cards.length; i++) { 879 if (!cards[i].id) { cards[i].id = 'pogoda-dock-' + (cards[i].getAttribute('data-widget') || i); } 880 dockRefresh(cards[i]); 881 } 882 var tabs = wrap.querySelectorAll('.pogoda-dock-tab'); 883 for (var k = 0; k < tabs.length; k++) { 884 var id = tabs[k].getAttribute('data-for') || ''; 885 if (!wrap.querySelector('.pogoda[data-widget="' + id + '"]')) { 886 // плаÑÐºÑ Ð·Ð°ÐºÑили ÑанÑÑе в ÑÑй ÑеÑÑÑ â вкладка Ñй не поÑÑÑбна 887 tabs[k].parentNode.removeChild(tabs[k]); 888 continue; 889 } 890 tabs[k].addEventListener('click', function () { 891 var wid = this.getAttribute('data-for'); 892 var opening = this.getAttribute('aria-expanded') !== 'true'; 893 dockOpen(wrap, opening ? wid : null); 894 if (opening) { 895 // ÐÑдкÑиÑа вкладка Ð¼Ð°Ñ Ð±ÑÑи Ð²Ð¸Ð´Ð¸Ð¼Ð¾Ñ Ñ Ð¿ÑокÑÑÑÐ½Ð¾Ð¼Ñ ÑÑÐ´ÐºÑ (без 896 // scrollIntoView â Ñой мÑг би пÑокÑÑÑиÑи й ÑÐ°Ð¼Ñ ÑÑоÑÑнкÑ). 897 var strip = this.parentNode; 898 if (strip && strip.scrollWidth > strip.clientWidth) { 899 var l = this.offsetLeft, r = l + this.offsetWidth; 900 if (r > strip.scrollLeft + strip.clientWidth) { strip.scrollLeft = r - strip.clientWidth + 4; }
901 else if (l < strip.scrollLeft) { strip.scrollLeft = Math.max(0, l - 4); } 902 } 903 } 904 }); 905 } 906 var hide = q(bar, '.pogoda-dock-hide'); 907 if (hide) { 908 hide.addEventListener('click', function () { 909 // Ðоки плаÑка вÑдкÑиÑа, â лиÑе згоÑÑÐ°Ñ ÑÑ: ÑÑ Ð¾Ð²Ð°Ñи веÑÑ Ð´Ð¾Ðº 910 // випадковим доÑиком поÑÑÑ Ñз Ð²ÐºÐ»Ð°Ð´ÐºÐ¾Ñ Ð½Ðµ можна. 911 if (wrap.classList.contains('pogoda-dock-open')) { dockOpen(wrap, null); return; } 912 if (wrap.parentNode) { wrap.parentNode.removeChild(wrap); } 913 if (!isPreviewWrap(wrap)) { store('session', 'pogoda_dock_closed', '1'); } 914 }); 915 } 916 // ÐоÑик поза доком Ñ Escape згоÑÑаÑÑÑ Ð²ÑдкÑиÑÑ Ð¿Ð»Ð°ÑкÑ. pointerdown â 917 // бо iOS Safari не Ñле click на document за доÑиком до звиÑайного ÑекÑÑÑ. 918 var outside = function (e) { 919 var t = e.target; 920 // Ðнопка «ÐоказаÑи каÑÑÑ/ÑеÑвÑÑ» замÑнÑÑ Ñебе на iframe Ñ Ð²Ð»Ð°ÑÐ½Ð¾Ð¼Ñ 921 // обÑобникÑ, Ñож на Ð¼Ð¾Ð¼ÐµÐ½Ñ click ÑÑ Ð²Ð¶Ðµ Ð½ÐµÐ¼Ð°Ñ Ð² докÑменÑÑ â Ñакий 922 // доÑик не «поза доком». 923 if (!t || !document.documentElement.contains(t)) { return; } 924 if (wrap.classList.contains('pogoda-dock-open') && dockMobile() && !wrap.contains(t)) { dockOpen(wrap, null); } 925 }; 926 document.addEventListener(window.PointerEvent ? 'pointerdown' : 'touchstart', outside, { passive: true }); 927 document.addEventListener('click', outside); 928 document.addEventListener('keydown', function (e) { 929 if ((e.key === 'Escape' || e.key === 'Esc') && wrap.classList.contains('pogoda-dock-open')) { dockOpen(wrap, null); } 930 }); 931 // ÐовоÑÐ¾Ñ Ð¿Ð»Ð°Ð½ÑеÑа в деÑкÑÐ¾Ð¿Ð½Ñ ÑиÑинÑ: ÑÑÐ¾Ñ Ð·Ð½Ð¾Ð²Ñ ÑÑлком, без вÑдкÑиÑÐ¾Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ¸. 932 if (window.matchMedia) { 933 var mq = window.matchMedia(DOCK_MQ); 934 var onChange = function () { if (!mq.matches) { dockOpen(wrap, null); } }; 935 if (mq.addEventListener) { mq.addEventListener('change', onChange); } 936 else if (mq.addListener) { mq.addListener(onChange); } 937 } 938 } 939 940 function boot() { 941 var floating = document.querySelectorAll('.pogoda-floating-wrap:not([data-preview]) .pogoda'); 942 for (var j = 0; j < floating.length; j++) { 943 var wid = floating[j].getAttribute('data-widget') || 'w'; 944 if (store('session', 'pogoda_closed_' + wid) === '1') { removeCard(floating[j]); } 945 } 946 var wraps = document.querySelectorAll('.pogoda-floating-wrap'); 947 for (var w = 0; w < wraps.length; w++) { initDock(wraps[w]); } 948 var cards = document.querySelectorAll('.pogoda'); 949 for (var i = 0; i < cards.length; i++) { 950 var card = cards[i]; 951 initClose(card); 952 switch (card.getAttribute('data-widget')) { 953 case 'weather': initWeather(card); break; 954 case 'losses': initLosses(card); break; 955 case 'map': initMap(card); break; 956 case 'rates': initRates(card); break; 957 case 'metals': initMetals(card); break; 958 case 'converter': initConverter(card); break; 959 case 'crypto': initRates(card); break; 960 case 'calc': initCalc(card); break; 961 case 'partners': initPartner(card); break; 962 } 963 } 964 } 965 966 if (document.readyState === 'loading') { 967 document.addEventListener('DOMContentLoaded', boot); 968 } else { 969 boot(); 970 } 971})();
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.