1(function () { 2 "use strict"; 3 4 var PACKAGE_CLASS_PREFIX = "tvpkg-"; 5 var MAX_PARENT_LOOKUP = 6; 6 var DATA_URL = window.TV_DATA_URL || "_userdata/include/tv_data.php"; 7 8 var dataCache = null; 9 var dataPending = false; 10 var gridCardsByKey = Object.create(null); 11 var gridRenderToken = 0; 12 13 function toArray(list) { 14 return Array.prototype.slice.call(list || []); 15 } 16 17 function normalizeKey(input) { 18 var s = String(input || "").toLowerCase(); 19 s = s.replace(/\+/g, " plus "); 20 s = s.replace(/&/g, " and "); 21 s = s.replace(/[^a-z0-9]+/g, ""); 22 return s; 23 } 24 25 function findPackageWrapper(fromNode) { 26 var node = fromNode; 27 var depth = 0; 28 29 while (node && node !== document.body && depth <= MAX_PARENT_LOOKUP) { 30 if (node.nodeType === 1 && node.classList && node.classList.length > 0) { 31 var prefixedClasses = toArray(node.classList).filter(function (cls) { 32 return cls.indexOf(PACKAGE_CLASS_PREFIX) === 0; 33 }); 34 35 if (prefixedClasses.length > 0) { 36 var cls = prefixedClasses[0]; 37 return { 38 element: node, 39 packageKey: cls.slice(PACKAGE_CLASS_PREFIX.length) 40 }; 41 } 42 } 43 44 node = node.parentElement; 45 depth += 1; 46 } 47 48 return null; 49 } 50 51 function getPackageLabel(wrapperElement, shortNode) { 52 var fromWrapper = wrapperElement && wrapperElement.dataset ? (wrapperElement.dataset.label || "").trim() : ""; 53 if (fromWrapper) { 54 return fromWrapper; 55 } 56 57 var labelNode = shortNode ? shortNode.querySelector("[data-label]") : null; 58 if (labelNode) { 59 var fromContent = (labelNode.getAttribute("data-label") || "").trim(); 60 if (fromContent) { 61 return fromContent; 62 } 63 } 64 65 return ""; 66 } 67 68 function readPackages() { 69 var shortNodes = toArray(document.querySelectorAll(".text_short")); 70 var results = []; 71 var seen = Object.create(null); 72 73 shortNodes.forEach(function (shortNode, index) { 74 var wrapperData = findPackageWrapper(shortNode); 75 var key = ""; 76 var label = ""; 77 78 if (wrapperData && wrapperData.element) { 79 key = (wrapperData.element.dataset && wrapperData.element.dataset.package) || wrapperData.packageKey || ""; 80 label = getPackageLabel(wrapperData.element, shortNode); 81 } 82 83 if (!key || !label) { 84 return; 85 } 86 87 var norm = normalizeKey(key); 88 if (seen[norm]) { 89 return; 90 } 91 seen[norm] = true; 92 93 results.push({ 94 key: key, 95 keyNorm: norm, 96 label: label, 97 labelNorm: normalizeKey(label), 98 html: shortNode.innerHTML, 99 order: Number((wrapperData && wrapperData.element && wrapperData.element.dataset && wrapperData.element.dataset.order) || index), 100 isDefault: !!(wrapperData && wrapperData.element && wrapperData.element.dataset && (wrapperData.element.dataset.default === "1" || wrapperData.element.dataset.default === "true")) 101 }); 102 }); 103 104 results.sort(function (a, b) { 105 return a.order - b.order; 106 }); 107 108 return results; 109 } 110 111 function ensureDescriptionTarget() { 112 var target = document.querySelector("#package-description, [data-tv-description]"); 113 if (target) { 114 return target; 115 } 116 117 var auto = document.createElement("div"); 118 auto.id = "package-description"; 119 document.body.appendChild(auto); 120 return auto; 121 } 122 123 function ensureSwitcherMounts(target) { 124 var mounts = toArray(document.querySelectorAll(".package-switcher, [data-tv-switcher]")); 125 if (mounts.length > 0) { 126 return mounts; 127 } 128 129 var div = document.createElement("div"); 130 div.className = "package-switcher"; 131 target.parentNode.insertBefore(div, target); 132 return [div]; 133 } 134 135 function createButton(pkg) { 136 var btn = document.createElement("button"); 137 btn.type = "button"; 138 btn.dataset.package = pkg.key; 139 btn.textContent = pkg.label; 140 return btn; 141 } 142 143 function getGridTarget() { 144 return document.querySelector("#channels-grid, [data-tv-grid]"); 145 } 146 147 function getColumnsTarget() { 148 return document.querySelector("#channels-columns, [data-tv-channels-columns]"); 149 } 150 151 function getPopupTarget() { 152 return document.querySelector("#tvpopup, [data-tv-popup]"); 153 } 154 155 function ensureGridAnimationStyles() { 156 if (document.getElementById("tv-grid-dynamic-styles")) { 157 return; 158 } 159 160 var style = document.createElement("style"); 161 style.id = "tv-grid-dynamic-styles"; 162 style.textContent = 163 "#channels-grid .channel{" + 164 "display:flex;align-items:center;justify-content:center;" + 165 "position:relative;overflow:hidden;" + 166 "background-color:#ddd;" + 167 "background-image:radial-gradient(circle at center,rgba(255,255,255,.5) 0%,rgba(255,255,255,.15) 40%,rgba(0,0,0,.08) 100%);" + 168 "border:1px solid rgba(0,0,0,.14);" + 169 "border-radius:12px;" + 170 "box-shadow:inset 0 1px 0 rgba(255,255,255,.35),0 8px 18px rgba(0,0,0,.12);" + 171 "transform-origin:center center;will-change:transform,opacity;" +
172 "transform:translate(var(--flip-x,0),var(--flip-y,0)) rotateX(var(--rx,0)) rotateY(var(--ry,0)) scale(var(--hover-scale,1));" + 173 "transition:transform 760ms cubic-bezier(0.22,1,0.36,1),opacity 360ms ease,box-shadow 260ms ease,border-color 260ms ease;" + 174 "}" + 175 "#channels-grid .channel.is-entering{opacity:0;transform:translate(var(--flip-x,0),var(--flip-y,0)) rotateX(var(--rx,0)) rotateY(var(--ry,0)) scale(.82);}" + 176 "#channels-grid .channel:hover{border-color:rgba(0,0,0,.22);box-shadow:inset 0 1px 0 rgba(255,255,255,.45),0 12px 24px rgba(0,0,0,.2);}" + 177 "#channels-grid .channel img{display:block;width:96%;height:96%;margin:auto;object-fit:contain;pointer-events:none;}"; 178 document.head.appendChild(style); 179 } 180 181 function getChannelKey(ch) { 182 if (ch && (ch.id || ch.id === 0)) { 183 return "id-" + String(ch.id); 184 } 185 return "n-" + String(ch && ch.number ? ch.number : "") + "-" + normalizeKey(ch && ch.name ? ch.name : ""); 186 } 187 188 function createGridCard(ch, popup) { 189 var el = document.createElement("div"); 190 el.className = "channel is-entering"; 191 el.style.display = "flex"; 192 el.style.alignItems = "center"; 193 el.style.justifyContent = "center"; 194 el.style.setProperty("--flip-x", "0px"); 195 el.style.setProperty("--flip-y", "0px"); 196 el.style.setProperty("--rx", "0deg"); 197 el.style.setProperty("--ry", "0deg"); 198 el.style.setProperty("--hover-scale", "1"); 199 200 el.addEventListener("mouseenter", function (e) { 201 if (!popup || !el._channelData) { 202 return; 203 } 204 205 var c = el._channelData; 206 popup.innerHTML = "<strong>Nr. " + (c.number || "-") + " " + escapeHtml(c.name || "") + "</strong><br><strong>" + escapeHtml(c.category || "inne") + "</strong>"; 207 popup.style.left = e.clientX + 12 + "px"; 208 popup.style.top = e.clientY + 12 + "px"; 209 popup.classList.add("visible"); 210 }); 211 212 el.addEventListener("mouseleave", function () { 213 if (popup) { 214 popup.classList.remove("visible"); 215 } 216 el.style.setProperty("--rx", "0deg"); 217 el.style.setProperty("--ry", "0deg"); 218 el.style.setProperty("--hover-scale", "1"); 219 }); 220 221 el.addEventListener("mousemove", function (e) { 222 var rect = el.getBoundingClientRect(); 223 var x = e.clientX - rect.left; 224 var y = e.clientY - rect.top; 225 var nx = ((x / rect.width) * 2) - 1; 226 var ny = ((y / rect.height) * 2) - 1; 227 var maxTilt = 6.5; 228 var rotateY = nx * maxTilt; 229 var rotateX = -ny * maxTilt; 230 el.style.setProperty("--rx", rotateX.toFixed(2) + "deg"); 231 el.style.setProperty("--ry", rotateY.toFixed(2) + "deg"); 232 el.style.setProperty("--hover-scale", "1.035"); 233 }); 234 235 updateGridCard(el, ch); 236 requestAnimationFrame(function () { 237 el.classList.remove("is-entering"); 238 }); 239 return el; 240 } 241 242 function updateGridCard(el, ch) { 243 el.dataset.number = String(ch.number || ""); 244 el.dataset.category = ch.category || "inne"; 245 el._channelData = ch; 246 247 if (ch.picon_url) { 248 el.innerHTML = '<img src="' + ch.picon_url + '" alt="' + escapeHtml(ch.name || "") + '">'; 249 } else { 250 el.innerHTML = '<span>' + escapeHtml((ch.number ? (ch.number + " ") : "") + (ch.name || "")) + "</span>"; 251 } 252 } 253 254 function getVisiblePositions(grid) { 255 var map = Object.create(null);
256 toArray(grid.querySelectorAll(".channel")).forEach(function (el) { 257 var key = el.dataset.channelKey; 258 if (key) { 259 map[key] = el.getBoundingClientRect(); 260 } 261 }); 262 return map; 263 } 264 265 function animateGridFlip(grid, oldPositions) { 266 toArray(grid.querySelectorAll(".channel")).forEach(function (el) { 267 var key = el.dataset.channelKey; 268 var oldPos = oldPositions[key]; 269 if (!oldPos) { 270 return; 271 } 272 273 var newPos = el.getBoundingClientRect(); 274 var dx = oldPos.left - newPos.left; 275 var dy = oldPos.top - newPos.top; 276 if (!dx && !dy) { 277 return; 278 } 279 280 el.style.transition = "none"; 281 el.style.setProperty("--flip-x", dx + "px"); 282 el.style.setProperty("--flip-y", dy + "px"); 283 el.offsetHeight; 284 el.style.transition = "transform 760ms cubic-bezier(0.22,1,0.36,1),opacity 360ms ease,box-shadow 260ms ease,border-color 260ms ease"; 285 el.style.setProperty("--flip-x", "0px"); 286 el.style.setProperty("--flip-y", "0px"); 287 }); 288 } 289 290 function renderGrid(channels) { 291 var grid = getGridTarget(); 292 if (!grid) { 293 return; 294 } 295 296 ensureGridAnimationStyles(); 297 var popup = getPopupTarget(); 298 var oldPositions = getVisiblePositions(grid); 299 var wanted = Object.create(null); 300 gridRenderToken += 1; 301 var token = gridRenderToken; 302 303 channels.forEach(function (ch) { 304 var key = getChannelKey(ch); 305 wanted[key] = true; 306 307 var card = gridCardsByKey[key]; 308 if (!card) { 309 card = createGridCard(ch, popup); 310 card.dataset.channelKey = key; 311 gridCardsByKey[key] = card; 312 } else { 313 updateGridCard(card, ch); 314 } 315 316 card._removeToken = 0; 317 card.style.opacity = ""; 318 card.style.transform = ""; 319 grid.appendChild(card); 320 }); 321 322 Object.keys(gridCardsByKey).forEach(function (key) { 323 if (wanted[key]) { 324 return; 325 } 326 var card = gridCardsByKey[key]; 327 if (card && card.parentNode === grid) { 328 card._removeToken = token; 329 card.style.opacity = "0"; 330 card.style.transform = "scale(0.8)"; 331 setTimeout(function () { 332 if (card._removeToken !== token) { 333 return; 334 } 335 if (card.parentNode === grid) { 336 grid.removeChild(card); 337 } 338 delete gridCardsByKey[key]; 339 }, 320); 340 } else { 341 delete gridCardsByKey[key]; 342 } 343 }); 344 345 requestAnimationFrame(function () { 346 animateGridFlip(grid, oldPositions); 347 }); 348 } 349 350 function groupByCategory(channels) { 351 var grouped = Object.create(null); 352 353 channels.forEach(function (ch) { 354 var cat = ch.category || "inne"; 355 if (!grouped[cat]) { 356 grouped[cat] = []; 357 } 358 grouped[cat].push(ch); 359 }); 360 361 return grouped; 362 } 363 364 function renderColumns(channels) { 365 var columnsRoot = getColumnsTarget(); 366 if (!columnsRoot) { 367 return; 368 } 369 370 columnsRoot.innerHTML = ""; 371 372 if (!channels || channels.length === 0) { 373 return; 374 } 375 376 var grouped = groupByCategory(channels); 377 var categoryNames = Object.keys(grouped); 378 379 var columns = [0, 1, 2].map(function () { 380 var col = document.createElement("div"); 381 col.className = "channels-column"; 382 col._count = 0; 383 columnsRoot.appendChild(col); 384 return col; 385 }); 386 387 categoryNames.forEach(function (category) { 388 var list = grouped[category]; 389 list.sort(function (a, b) { 390 var an = Number(a.number || 0); 391 var bn = Number(b.number || 0); 392 if (an !== bn) { 393 return an - bn; 394 } 395 return String(a.name || "").localeCompare(String(b.name || "")); 396 }); 397 398 var target = columns.reduce(function (a, b) { 399 return a._count <= b._count ? a : b; 400 }); 401 402 var group = document.createElement("div"); 403 group.className = "category-group"; 404 405 var title = document.createElement("div"); 406 title.className = "category-title"; 407 title.textContent = category + " (" + list.length + ")"; 408 409 var items = document.createElement("div"); 410 items.className = "category-channels"; 411 412 list.forEach(function (ch) { 413 var item = document.createElement("div"); 414 item.className = "channel-list-item"; 415 item.innerHTML = "<span>" + escapeHtml(String(ch.number || "")) + "</span>" + escapeHtml(ch.name || ""); 416 items.appendChild(item); 417 }); 418 419 group.appendChild(title); 420 group.appendChild(items); 421 target.appendChild(group); 422 target._count += list.length; 423 }); 424 } 425 426 function escapeHtml(value) { 427 return String(value || "") 428 .replace(/&/g, "&") 429 .replace(/</g, "<") 430 .replace(/>/g, ">") 431 .replace(/\"/g, """) 432 .replace(/'/g, "'"); 433 } 434 435 function fetchData(callback) { 436 if (dataCache) { 437 callback(null, dataCache); 438 return; 439 } 440 441 if (dataPending) { 442 setTimeout(function () { 443 fetchData(callback); 444 }, 100); 445 return; 446 } 447 448 dataPending = true; 449 450 var xhr = new XMLHttpRequest(); 451 xhr.open("GET", DATA_URL, true); 452 xhr.onreadystatechange = function () { 453 if (xhr.readyState !== 4) { 454 return; 455 } 456 457 dataPending = false;
458 459 if (xhr.status < 200 || xhr.status >= 300) { 460 callback(new Error("HTTP " + xhr.status)); 461 return; 462 } 463 464 try { 465 dataCache = JSON.parse(xhr.responseText); 466 callback(null, dataCache); 467 } catch (err) { 468 callback(err); 469 } 470 }; 471 472 xhr.send(); 473 } 474 475 function resolveChannelsForPackage(pkg, data) { 476 if (!data || !data.channels_by_package) { 477 return []; 478 } 479 480 var candidates = [pkg.keyNorm, pkg.labelNorm, normalizeKey(pkg.key), normalizeKey(pkg.label)]; 481 var map = data.channels_by_package; 482 var aliases = data.package_alias_to_key || {}; 483 484 var i; 485 for (i = 0; i < candidates.length; i += 1) { 486 var candidate = candidates[i]; 487 if (!candidate) { 488 continue; 489 } 490 491 if (map[candidate]) { 492 return map[candidate]; 493 } 494 495 if (aliases[candidate] && map[aliases[candidate]]) { 496 return map[aliases[candidate]]; 497 } 498 } 499 500 return []; 501 } 502 503 function init() { 504 var packages = readPackages(); 505 if (packages.length === 0) { 506 console.warn("tv.js: Nie znaleziono pakietow. Uzyj klasy z prefiksem '" + PACKAGE_CLASS_PREFIX + "' i data-label."); 507 return; 508 } 509 510 var target = ensureDescriptionTarget(); 511 var switchers = ensureSwitcherMounts(target); 512 switchers.forEach(function (switcher) { 513 switcher.innerHTML = ""; 514 }); 515 516 var map = Object.create(null); 517 packages.forEach(function (pkg) { 518 map[pkg.key] = pkg; 519 switchers.forEach(function (switcher) { 520 switcher.appendChild(createButton(pkg)); 521 }); 522 }); 523 524 function setActive(key) { 525 switchers.forEach(function (switcher) { 526 toArray(switcher.querySelectorAll("button[data-package]")).forEach(function (btn) { 527 btn.classList.toggle("active", btn.dataset.package === key); 528 }); 529 }); 530 } 531 532 function renderChannelsForPackage(pkg) { 533 fetchData(function (err, data) { 534 if (err) { 535 console.warn("tv.js: Blad pobierania danych kanaÅow:", err); 536 renderGrid([]); 537 renderColumns([]); 538 return; 539 } 540 541 var channels = resolveChannelsForPackage(pkg, data); 542 renderGrid(channels); 543 renderColumns(channels); 544 }); 545 } 546 547 function applyPackage(key) { 548 var pkg = map[key]; 549 if (!pkg) { 550 return; 551 } 552 553 target.innerHTML = pkg.html; 554 setActive(key); 555 renderChannelsForPackage(pkg); 556 } 557 558 switchers.forEach(function (switcher) { 559 toArray(switcher.querySelectorAll("button[data-package]")).forEach(function (btn) { 560 btn.addEventListener("click", function () { 561 applyPackage(btn.dataset.package); 562 }); 563 }); 564 }); 565 566 var defaultPkg = null; 567 for (var i = 0; i < packages.length; i += 1) { 568 if (packages[i].isDefault) { 569 defaultPkg = packages[i]; 570 break; 571 } 572 } 573 if (!defaultPkg) { 574 defaultPkg = packages[0]; 575 } 576 577 applyPackage(defaultPkg.key); 578 } 579 580 if (document.readyState === "loading") { 581 document.addEventListener("DOMContentLoaded", init); 582 } else { 583 init(); 584 } 585})();
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.