1/* ===================================================== 2 Pokedex Explorer â Client Logic 3 ===================================================== */ 4 5(function () { 6 'use strict'; 7 8 // ---- i18n (Issue #1625 B, icerik sayfalari dilimi) ---- 9 // Kullaniciya gorunen metinler artik bu dosyada SABIT DEGIL: Pokedex/Index.cshtml kok 10 // container'a data-i18n-* attribute'lari basar, sunucu onlari Index.resx / Index.en.resx'ten 11 // doldurur. Ayni desen basket.js (#1625 B ilk dilim) / destek.js (#1613). Attribute yoksa 12 // (or. onbellekten gelen eski HTML) bugunku TR metne duseriz -- davranis degismez. 13 const i18nRoot = document.querySelector('.container-fluid[data-i18n-remove-binder-confirm]'); 14 function t(name, fallback) { 15 if (!i18nRoot) return fallback; 16 const value = i18nRoot.getAttribute('data-i18n-' + name); 17 return (value === null || value === '') ? fallback : value; 18 } 19 20 // ---- DOM refs ---- 21 const searchInput = document.getElementById('pokemonSearch'); 22 const pokemonItems = document.querySelectorAll('.pokemon-item'); 23 const regionSections = document.querySelectorAll('.region-section'); 24 const emptyMsg = document.getElementById('emptySearchMessage'); 25 const filterBtns = document.querySelectorAll('.pokedex-filter-btn'); 26 27 let currentFilter = 'all'; // 'all' | 'collected' | 'missing' 28 29 // ---- Search + Filter ---- 30 function applyFilters() { 31 if (!searchInput) return; 32 33 var term = searchInput.value.trim().toLowerCase(); 34 var totalVisible = 0; 35 36 pokemonItems.forEach(function (item) { 37 var name = item.dataset.pokemonName || ''; 38 var id = item.dataset.pokemonId || ''; 39 var isCollected = item.classList.contains('collected'); 40 41 // Arama eslesmesi 42 var matchesSearch = !term || name.includes(term) || id.toString().includes(term); 43 44 // Filtre eslesmesi 45 var matchesFilter = true; 46 if (currentFilter === 'collected') { 47 matchesFilter = isCollected; 48 } else if (currentFilter === 'missing') { 49 matchesFilter = !isCollected; 50 } 51 52 if (matchesSearch && matchesFilter) { 53 item.classList.remove('hidden'); 54 totalVisible++; 55 } else { 56 item.classList.add('hidden'); 57 } 58 }); 59 60 // Bos bolgeleri gizle 61 regionSections.forEach(function (section) { 62 var visibleInRegion = section.querySelectorAll('.pokemon-item:not(.hidden)').length; 63 if (visibleInRegion === 0 && (term || currentFilter !== 'all')) { 64 section.classList.add('hidden'); 65 } else { 66 section.classList.remove('hidden'); 67 } 68 69 // Bolge progress badge guncelle (filtre aktifken) 70 var badge = section.querySelector('.region-progress-badge'); 71 if (badge && currentFilter !== 'all') { 72 badge.style.display = 'none'; 73 } else if (badge) { 74 badge.style.display = ''; 75 } 76 }); 77 78 // Bos durum mesaji 79 if (emptyMsg) { 80 emptyMsg.style.display = totalVisible === 0 ? 'block' : 'none'; 81 } 82 } 83 84 if (searchInput) { 85 searchInput.addEventListener('input', applyFilters); 86 if (searchInput.value) applyFilters(); 87 } 88 89 // ---- Filter Buttons ---- 90 filterBtns.forEach(function (btn) { 91 btn.addEventListener('click', function () { 92 filterBtns.forEach(function (b) { b.classList.remove('active'); }); 93 btn.classList.add('active');
94 currentFilter = btn.dataset.filter || 'all'; 95 applyFilters(); 96 }); 97 }); 98 99 // ---- Bolge Badge Scroll ---- 100 document.querySelectorAll('.region-jump-badge').forEach(function (badge) { 101 badge.addEventListener('click', function () { 102 var target = badge.dataset.regionTarget; 103 if (!target) return; 104 var section = document.querySelector('.region-section[data-region-name="' + target + '"]'); 105 if (section) { 106 section.scrollIntoView({ behavior: 'smooth', block: 'start' }); 107 } 108 }); 109 }); 110 111 // ---- Binder Selection Modal ---- 112 var modalOverlay = document.getElementById('binderModalOverlay'); 113 114 window.openBinderModal = function () { 115 if (modalOverlay) { 116 modalOverlay.classList.add('show'); 117 } 118 }; 119 120 window.closeBinderModal = function () { 121 if (modalOverlay) { 122 modalOverlay.classList.remove('show'); 123 } 124 }; 125 126 // Overlay tiklamasi ile kapat 127 if (modalOverlay) { 128 modalOverlay.addEventListener('click', function (e) { 129 if (e.target === modalOverlay) { 130 window.closeBinderModal(); 131 } 132 }); 133 } 134
135 // ESC ile kapat 136 document.addEventListener('keydown', function (e) { 137 if (e.key === 'Escape' && modalOverlay && modalOverlay.classList.contains('show')) { 138 window.closeBinderModal(); 139 } 140 }); 141 142 // ---- Binder Sec ---- 143 window.selectPokedexBinder = function (binderId) { 144 fetch('/Pokedex/SetPokedexBinder', { 145 method: 'POST', 146 headers: { 147 'Content-Type': 'application/json', 148 'RequestVerificationToken': getAntiForgeryToken() 149 }, 150 body: JSON.stringify({ binderId: binderId }) 151 }) 152 .then(function (res) { return res.json(); }) 153 .then(function (data) { 154 if (data.success) { 155 window.location.reload(); 156 } 157 }) 158 .catch(function (err) { 159 console.error('Binder secilirken hata:', err); 160 }); 161 }; 162 163 // ---- Yeni Binder Olustur ---- 164 window.createPokedexBinder = function () { 165 var nameInput = document.getElementById('newBinderName'); 166 var name = nameInput ? nameInput.value.trim() : ''; 167 168 fetch('/Pokedex/CreatePokedexBinder', { 169 method: 'POST', 170 headers: { 171 'Content-Type': 'application/json', 172 'RequestVerificationToken': getAntiForgeryToken() 173 }, 174 body: JSON.stringify({ name: name || 'Pokédex Koleksiyonum' }) 175 }) 176 .then(function (res) { return res.json(); }) 177 .then(function (data) { 178 if (data.success) { 179 window.location.reload(); 180 } 181 }) 182 .catch(function (err) { 183 console.error('Binder olusturulurken hata:', err); 184 }); 185 }; 186 187 // ---- Pokedex Binderi Kaldir ---- 188 window.removePokedexBinder = function () { 189 if (!confirm(t('remove-binder-confirm', 'Pokédex binder eÅleÅtirmesini kaldırmak istediÄinize emin misiniz?'))) { 190 return; 191 } 192 193 fetch('/Pokedex/RemovePokedexBinder', { 194 method: 'POST', 195 headers: { 196 'Content-Type': 'application/json', 197 'RequestVerificationToken': getAntiForgeryToken() 198 } 199 }) 200 .then(function (res) { return res.json(); }) 201 .then(function () { 202 window.location.reload(); 203 }) 204 .catch(function (err) { 205 console.error('Binder kaldirilirken hata:', err); 206 }); 207 }; 208 209 // ---- Progress Circle Animation ---- 210 function animateProgressCircle() { 211 var circle = document.querySelector('.progress-circle-fill'); 212 if (!circle) return; 213 214 var percent = parseFloat(circle.dataset.percent || 0); 215 var radius = 34; 216 var circumference = 2 * Math.PI * radius; 217 218 circle.style.strokeDasharray = circumference; 219 circle.style.strokeDashoffset = circumference; 220 221 // Animasyon baslat 222 requestAnimationFrame(function () { 223 var offset = circumference - (percent / 100) * circumference; 224 circle.style.strokeDashoffset = offset; 225 }); 226 } 227 228 animateProgressCircle(); 229 230 // ---- Anti-forgery token helper ---- 231 function getAntiForgeryToken() { 232 var tokenInput = document.querySelector('input[name="__RequestVerificationToken"]'); 233 if (tokenInput) return tokenInput.value; 234 235 // Cookie'den bul 236 var cookies = document.cookie.split(';'); 237 for (var i = 0; i < cookies.length; i++) { 238 var cookie = cookies[i].trim(); 239 if (cookie.startsWith('.AspNetCore.Antiforgery')) { 240 return cookie.split('=')[1]; 241 } 242 } 243 return ''; 244 } 245 246})();
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.