1(function(){ 2 function qs(sel){ return document.querySelector(sel); } 3 function qsa(sel){ return Array.prototype.slice.call(document.querySelectorAll(sel)); } 4 function getMainNav(){ 5 return document.getElementById('mobileMainNav') || qs('[data-mobile-main-nav]') || qs('[data-nav]'); 6 } 7 function getMobileMenuBackdrop(){ 8 var backdrop = document.querySelector('.mobile-menu-backdrop'); 9 if(!backdrop){ 10 backdrop = document.createElement('button'); 11 backdrop.type = 'button'; 12 backdrop.className = 'mobile-menu-backdrop'; 13 backdrop.setAttribute('aria-label','Menüyü kapat'); 14 backdrop.setAttribute('tabindex','-1'); 15 document.body.appendChild(backdrop); 16 } 17 return backdrop; 18 } 19 function closeRightMenu(){ 20 const nav = getMainNav(); 21 if(nav){ 22 nav.classList.remove('open'); 23 nav.setAttribute('aria-hidden','true'); 24 nav.style.visibility = ''; 25 nav.style.pointerEvents = ''; 26 nav.style.opacity = ''; 27 nav.style.filter = ''; 28 } 29 var backdrop = document.querySelector('.mobile-menu-backdrop'); 30 if(backdrop){ backdrop.classList.remove('is-open'); } 31 qsa('[data-nav-toggle]').forEach(function(btn){ btn.setAttribute('aria-expanded','false'); }); 32 document.body.classList.remove('nav-open','mobile-main-nav-open'); 33 } 34 var lastSideTrigger = null; 35 function isMobileSideMode(){ 36 return !window.matchMedia || window.matchMedia('(max-width: 980px)').matches; 37 } 38 function syncSideMenuState(menu, open){ 39 if(!menu) return; 40 var id = menu.id || ''; 41 if(id){ 42 qsa('[data-sidebar-toggle]').forEach(function(btn){ 43 if(btn.getAttribute('data-sidebar-toggle') === id){ 44 btn.setAttribute('aria-controls', id); 45 btn.setAttribute('aria-expanded', open ? 'true' : 'false'); 46 } 47 }); 48 } 49 if(isMobileSideMode()) menu.setAttribute('aria-hidden', open ? 'false' : 'true'); 50 else menu.removeAttribute('aria-hidden'); 51 } 52 function closeSideMenus(restoreFocus){ 53 qsa('.side-menu').forEach(function(menu){ 54 menu.classList.remove('open'); 55 syncSideMenuState(menu, false); 56 }); 57 document.body.classList.remove('side-open'); 58 var triggerToRestore = lastSideTrigger; 59 lastSideTrigger = null; 60 if(restoreFocus && triggerToRestore && typeof triggerToRestore.focus === 'function'){ 61 try { triggerToRestore.focus({preventScroll:true}); } catch(_e) { triggerToRestore.focus(); } 62 } 63 } 64 function focusSideMenu(menu){ 65 if(!menu) return; 66 var target = menu.querySelector('[data-admin-menu-search], [data-sidebar-close], a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])'); 67 if(target && typeof target.focus === 'function'){ 68 window.requestAnimationFrame(function(){ try { target.focus({preventScroll:true}); } catch(_e) { target.focus(); } }); 69 } 70 } 71 function syncAllSideMenuA11y(){ 72 qsa('.side-menu').forEach(function(menu){ syncSideMenuState(menu, menu.classList.contains('open')); }); 73 } 74 function openRightMenu(){ 75 closeSideMenus(); 76 const nav = getMainNav(); 77 if(nav){ 78 nav.classList.add('open'); 79 nav.setAttribute('aria-hidden','false'); 80 nav.style.visibility = 'visible'; 81 nav.style.pointerEvents = 'auto'; 82 nav.style.opacity = '1'; 83 nav.style.filter = 'none'; 84 getMobileMenuBackdrop().classList.add('is-open'); 85 qsa('[data-nav-toggle]').forEach(function(btn){ btn.setAttribute('aria-expanded','true'); }); 86 document.body.classList.add('nav-open','mobile-main-nav-open'); 87 } 88 } 89 function toggleRightMenu(){ 90 const nav = getMainNav(); 91 if(!nav) return; 92 if(nav.classList.contains('open')) closeRightMenu(); else openRightMenu(); 93 } 94 95 function syncMobilePanelOffsets(){ 96 var topbar = document.querySelector('.topbar'); 97 if(!topbar) return; 98 var rect = topbar.getBoundingClientRect(); 99 var height = Math.max(64, Math.ceil(rect.height || topbar.offsetHeight || 0)); 100 document.documentElement.style.setProperty('--wmt-topbar-height', height + 'px'); 101 } 102 103 document.addEventListener('DOMContentLoaded', function(){ 104 syncMobilePanelOffsets(); 105 if('ResizeObserver' in window){ 106 var panelTopbarObserverTarget = document.querySelector('.topbar'); 107 if(panelTopbarObserverTarget){ try { new ResizeObserver(syncMobilePanelOffsets).observe(panelTopbarObserverTarget); } catch(_e) {} } 108 } 109 const mainNav = getMainNav(); 110 if(mainNav && mainNav.parentElement !== document.body){ document.body.appendChild(mainNav); } 111 getMobileMenuBackdrop(); 112 const contextToggle = qs('[data-context-menu-toggle]'); 113 const allowedByLayout = document.body.classList.contains('mobile-context-allowed'); 114 const contextMenu = allowedByLayout ? (document.getElementById('userSide') || document.getElementById('adminSide')) : null; 115 if(contextMenu && contextToggle){ 116 document.body.classList.add('has-context-menu'); 117 contextToggle.removeAttribute('hidden'); 118 contextToggle.setAttribute('data-sidebar-toggle', contextMenu.id); 119 contextToggle.setAttribute('aria-controls', contextMenu.id); 120 contextToggle.setAttribute('aria-expanded', 'false'); 121 } else if(contextToggle) { 122 document.body.classList.remove('has-context-menu'); 123 contextToggle.removeAttribute('data-sidebar-toggle'); 124 contextToggle.removeAttribute('aria-controls'); 125 contextToggle.setAttribute('aria-expanded', 'false'); 126 contextToggle.setAttribute('hidden', 'hidden'); 127 }
128 qsa('[data-sidebar-toggle]').forEach(function(btn){ 129 var targetId = btn.getAttribute('data-sidebar-toggle'); 130 if(targetId){ btn.setAttribute('aria-controls', targetId); btn.setAttribute('aria-expanded', 'false'); } 131 }); 132 syncAllSideMenuA11y(); 133 }); 134 135 document.addEventListener('click', function(e){ 136 const navToggle = e.target.closest('[data-nav-toggle]'); 137 if(navToggle){ 138 // mobil ana menü tek kontrolcü tarafından yönetilir; eski yakalayıcı çift aç/kapat yapmasın. 139 if(window.matchMedia && window.matchMedia('(max-width: 850px)').matches){ return; } 140 e.preventDefault(); 141 e.stopPropagation(); 142 toggleRightMenu(); 143 return; 144 } 145 146 const sideBtn = e.target.closest('[data-sidebar-toggle]'); 147 if(sideBtn){ 148 e.preventDefault(); 149 e.stopPropagation(); 150 const id = sideBtn.getAttribute('data-sidebar-toggle'); 151 const menu = document.getElementById(id); 152 if(menu){ 153 closeRightMenu(); 154 const willOpen = !menu.classList.contains('open'); 155 closeSideMenus(false); 156 if(willOpen){ 157 lastSideTrigger = sideBtn; 158 menu.classList.add('open'); 159 syncSideMenuState(menu, true); 160 document.body.classList.add('side-open'); 161 focusSideMenu(menu); 162 } else { 163 syncSideMenuState(menu, false); 164 lastSideTrigger = null; 165 } 166 } 167 return; 168 } 169 170 if(e.target.closest('.mobile-menu-backdrop')){ 171 e.preventDefault(); 172 closeRightMenu(); 173 return; 174 } 175 176 if(e.target.closest('[data-nav-close]')){ 177 e.preventDefault(); 178 closeRightMenu(); 179 return; 180 } 181 182 if(e.target.closest('[data-sidebar-close]')){ 183 e.preventDefault(); 184 closeSideMenus(true); 185 return; 186 } 187 188 if(e.target.closest('[data-mobile-main-nav] a, [data-nav] a')){ 189 closeRightMenu(); 190 return; 191 } 192 193 if(e.target.closest('.side-menu a')){ 194 closeSideMenus(); 195 return; 196 } 197 198 if(document.body.classList.contains('nav-open') && !e.target.closest('[data-mobile-main-nav], [data-nav], [data-nav-toggle]')){ 199 e.preventDefault(); 200 closeRightMenu(); 201 return; 202 } 203 204 if(document.body.classList.contains('side-open') && !e.target.closest('.side-menu')){ 205 e.preventDefault(); 206 closeSideMenus(true); 207 } 208 }, true); 209 210 document.addEventListener('keydown', function(e){ 211 if(e.key === 'Escape'){ 212 closeRightMenu(); 213 closeSideMenus(true); 214 return; 215 } 216 if(e.key === 'Tab' && document.body.classList.contains('side-open')){ 217 var menu = qs('.side-menu.open'); 218 if(!menu) return; 219 var focusable = qsa('a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])').filter(function(node){ 220 return menu.contains(node) && node.getAttribute('aria-hidden') !== 'true' && node.offsetParent !== null; 221 }); 222 if(!focusable.length){ e.preventDefault(); return; } 223 var first = focusable[0], last = focusable[focusable.length - 1]; 224 if(e.shiftKey && document.activeElement === first){ e.preventDefault(); last.focus(); } 225 else if(!e.shiftKey && document.activeElement === last){ e.preventDefault(); first.focus(); } 226 } 227 }); 228 229 window.addEventListener('resize', function(){ syncMobilePanelOffsets(); syncAllSideMenuA11y(); }, { passive:true }); 230 if(window.visualViewport){ window.visualViewport.addEventListener('resize', syncMobilePanelOffsets, { passive:true }); } 231 232 document.addEventListener('click', function(e){ 233 const toggle = e.target.closest('[data-icon-toggle]'); 234 if(toggle){ 235 e.preventDefault(); 236 const picker = toggle.closest('[data-icon-picker]'); 237 if(!picker) return; 238 const willOpen = !picker.classList.contains('is-open'); 239 qsa('[data-icon-picker].is-open').forEach(function(item){ item.classList.remove('is-open'); var t=item.querySelector('[data-icon-toggle]'); if(t) t.setAttribute('aria-expanded','false'); }); 240 if(willOpen){ picker.classList.add('is-open'); toggle.setAttribute('aria-expanded','true'); } 241 return; 242 } 243 244 const iconBtn = e.target.closest('[data-icon-value]'); 245 if(iconBtn){ 246 const picker = iconBtn.closest('[data-icon-picker]'); 247 if(!picker) return; 248 e.preventDefault(); 249 const value = iconBtn.getAttribute('data-icon-value') || 'chat'; 250 const symbol = iconBtn.getAttribute('data-icon-symbol') || iconBtn.textContent.trim() || 'ð¬'; 251 const input = picker.querySelector('[data-icon-input]'); 252 const preview = picker.querySelector('[data-icon-preview]'); 253 const toggleBtn = picker.querySelector('[data-icon-toggle]'); 254 if(input) input.value = value; 255 if(preview) preview.textContent = symbol; 256 picker.querySelectorAll('[data-icon-value].selected').forEach(function(btn
256){ btn.classList.remove('selected'); }); 257 iconBtn.classList.add('selected'); 258 picker.classList.remove('is-open'); 259 if(toggleBtn) toggleBtn.setAttribute('aria-expanded','false'); 260 return; 261 } 262 263 if(!e.target.closest('[data-icon-picker]')){ 264 qsa('[data-icon-picker].is-open').forEach(function(item){ item.classList.remove('is-open'); var t=item.querySelector('[data-icon-toggle]'); if(t) t.setAttribute('aria-expanded','false'); }); 265 } 266 }); 267 268 269 window.addEventListener('resize', syncMobilePanelOffsets, { passive:true }); 270 window.addEventListener('orientationchange', syncMobilePanelOffsets, { passive:true }); 271 window.addEventListener('load', syncMobilePanelOffsets, { passive:true }); 272})(); 273 274/* koyu mod ve üst kullanıcı menüsü */ 275(function(){ 276 function qs(sel){ return document.querySelector(sel); } 277 function qsa(sel){ return Array.prototype.slice.call(document.querySelectorAll(sel)); } 278 function themePreference(){ 279 var saved = ''; 280 try { saved = localStorage.getItem('ffp_theme_mode') || ''; } catch(e) {} 281 if(saved === 'light' || saved === 'dark' || saved === 'auto') return saved; 282 var def = document.documentElement.getAttribute('data-default-theme') || 'light'; 283 return (def === 'dark' || def === 'auto') ? def : 'light'; 284 } 285 function resolveTheme(preference){ 286 if(preference === 'auto'){ 287 return (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) ? 'dark' : 'light'; 288 } 289 return preference === 'dark' ? 'dark' : 'light'; 290 } 291 function setTheme(preference, persist){ 292 preference = (preference === 'dark' || preference === 'auto') ? preference : 'light'; 293 var mode = resolveTheme(preference); 294 var themeTargets = [document.documentElement]; 295 if(document.body) themeTargets.push(document.body); 296 themeTargets.forEach(function(target){ 297 target.setAttribute('data-theme-preference', preference); 298 target.setAttribute('data-theme', mode); 299 target.classList.toggle('dark', mode === 'dark'); 300 target.classList.toggle('light', mode !== 'dark'); 301 target.style.colorScheme = mode; 302 }); 303 var themeMeta = document.querySelector('meta[data-theme-color]'); 304 if(themeMeta){ 305 var lightColor = themeMeta.getAttribute('data-light-color') || themeMeta.getAttribute('content') || '#2563eb'; 306 var darkColor = themeMeta.getAttribute('data-dark-color') || '#0b1220'; 307 themeMeta.setAttribute('content', mode === 'dark' ? darkColor : lightColor); 308 } 309 if(persist){ try { localStorage.setItem('ffp_theme_mode', preference); } catch(e) {} } 310 qsa('[data-theme-toggle]').forEach(function(btn){ 311 var icon = btn.querySelector('.theme-toggle-icon') || btn.querySelector('span'); 312 if(icon && !icon.querySelector('svg')){ icon.textContent = mode === 'dark' ? 'âï¸' : 'ð'; } 313 var stateLabel = btn.querySelector('[data-theme-state-label]'); 314 if(stateLabel){ stateLabel.textContent = preference === 'auto' ? ('Otomatik · ' + (mode === 'dark' ? 'Koyu' : 'Açık')) : (mode === 'dark' ? 'Koyu mod açık' : 'Açık mod açık'); } 315 var nextPreference = preference === 'light' ? 'dark' : (preference === 'dark' ? 'auto' : 'light'); 316 var nextLabel = nextPreference === 'dark' ? 'Koyu moda geç' : (nextPreference === 'auto' ? 'Otomatik temaya geç' : 'Açık moda geç'); 317 btn.setAttribute('aria-label', nextLabel); 318 btn.setAttribute('title', nextLabel); 319 btn.classList.toggle('is-dark', mode === 'dark'); 320 btn.classList.toggle('is-auto', preference === 'auto'); 321 btn.setAttribute('data-theme-preference', preference); 322 }); 323 } 324 function nextThemePreference(preference){ return preference === 'light' ? 'dark' : (preference === 'dark' ? 'auto' : 'light'); } 325 function closeUserMenus(){ 326 qsa('[data-user-menu].open').forEach(function(menu){ 327 menu.classList.remove('open'); 328 var btn = menu.querySelector('[data-user-menu-toggle]'); 329 if(btn) btn.setAttribute('aria-expanded','false'); 330 }); 331 } 332 document.addEventListener('DOMContentLoaded', function(){ 333 setTheme(themePreference(), false); 334 qsa('.user-menu-panel-v1100 a[href]').forEach(function(link){
335 try { 336 var target = new URL(link.href, window.location.href); 337 var currentPath = (window.location.pathname || '/').replace(/\/+$/, '') || '/'; 338 var targetPath = (target.pathname || '/').replace(/\/+$/, '') || '/'; 339 if(target.origin === window.location.origin && targetPath === currentPath){ 340 link.classList.add('is-current'); 341 link.setAttribute('aria-current','page'); 342 } 343 } catch(e) {} 344 }); 345 }); 346 document.addEventListener('click', function(e){ 347 var userCloseBtn = e.target.closest('[data-user-menu-close]'); 348 if(userCloseBtn){ 349 e.preventDefault(); 350 e.stopPropagation(); 351 var ownerMenu = userCloseBtn.closest('[data-user-menu]'); 352 var ownerToggle = ownerMenu ? ownerMenu.querySelector('[data-user-menu-toggle]') : null; 353 closeUserMenus(); 354 if(ownerToggle) ownerToggle.focus(); 355 return; 356 } 357 var themeBtn = e.target.closest('[data-theme-toggle]'); 358 if(themeBtn){ 359 e.preventDefault(); 360 setTheme(nextThemePreference(themePreference()), true); 361 return; 362 } 363 var userBtn = e.target.closest('[data-user-menu-toggle]'); 364 if(userBtn){ 365 e.preventDefault(); 366 e.stopPropagation(); 367 var menu = userBtn.closest('[data-user-menu]'); 368 if(!menu) return; 369 var willOpen = !menu.classList.contains('open'); 370 closeUserMenus(); 371 if(willOpen){ 372 menu.classList.add('open'); 373 userBtn.setAttribute('aria-expanded','true'); 374 var more = menu.querySelector('.user-menu-more-v1100'); 375 if(more) more.open = false; 376 } 377 return; 378 } 379 if(!e.target.closest('[data-user-menu]')) closeUserMenus(); 380 }); 381 if(window.matchMedia){ 382 var colorSchemeQuery = window.matchMedia('(prefers-color-scheme: dark)'); 383 var syncAutoTheme = function(){ if(themePreference() === 'auto') setTheme('auto', false); }; 384 if(colorSchemeQuery.addEventListener) colorSchemeQuery.addEventListener('change', syncAutoTheme); 385 else if(colorSchemeQuery.addListener) colorSchemeQuery.addListener(syncAutoTheme); 386 } 387 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeUserMenus(); }); 388})(); 389 390/* bildirim açılır menüsü ve mobil saÄ Ã§ekmece kaldırma */ 391(function(){ 392 function qs(sel){ return document.querySelector(sel); } 393 function qsa(sel){ return Array.prototype.slice.call(document.querySelectorAll(sel)); } 394 function closeNotifications(){ 395 qsa('[data-notification-menu].open').forEach(function(menu){ 396 menu.classList.remove('open'); 397 var btn = menu.querySelector('[data-notification-toggle]'); 398 if(btn) btn.setAttribute('aria-expanded','false'); 399 }); 400 } 401 function closeUsers(){ 402 qsa('[data-user-menu].open').forEach(function(menu){ 403 menu.classList.remove('open'); 404 var btn = menu.querySelector('[data-user-menu-toggle]'); 405 if(btn) btn.setAttribute('aria-expanded','false'); 406 }); 407 } 408 document.addEventListener('click', function(e){ 409 var closeBtn = e.target.closest('[data-notification-close]'); 410 if(closeBtn){ 411 e.preventDefault(); 412 e.stopPropagation(); 413 closeNotifications(); 414 return; 415 } 416 var notificationBtn = e.target.closest('[data-notification-toggle]'); 417 if(notificationBtn){ 418 e.preventDefault(); 419 e.stopPropagation(); 420 var menu = notificationBtn.closest('[data-notification-menu]'); 421 if(!menu) return; 422 var willOpen = !menu.classList.contains('open'); 423 closeNotifications(); 424 closeUsers(); 425 if(willOpen){ 426 menu.classList.add('open'); 427 notificationBtn.setAttribute('aria-expanded','true'); 428 } 429 return; 430 } 431 var userBtn = e.target.closest('[data-user-menu-toggle]'); 432 if(userBtn){ closeNotifications(); return; } 433 if(!e.target.closest('[data-notification-menu]')) closeNotifications(); 434 }, true); 435 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeNotifications(); }); 436})(); 437 438/* dil seçici */ 439(function(){ 440 function qsa(sel){ return Array.prototype.slice.call(document.querySelectorAll(sel)); } 441 function closeLanguageMenus(){ 442 qsa('[data-language-menu].open').forEach(function(menu){ 443 menu.classList.remove('open'); 444 var btn = menu.querySelector('[data-language-toggle]'); 445 if(btn) btn.setAttribute('aria-expanded','false'); 446 }); 447 } 448 document.addEventListener('click', function(e){ 449 var btn = e.target.closest('[data-language-toggle]'); 450 if(btn){ 451 e.preventDefault(); 452 e.stopPropagation(); 453 var menu = btn.closest('[data-language-menu]'); 454 if(!menu) return; 455 var willOpen = !menu.classList.contains('open'); 456 closeLanguageMenus(); 457 document.querySelectorAll('[data-user-menu].open,[data-notification-menu].open').forEach(function(item){ item.classList.remove('open'); }); 458 if(willOpen){ menu.classList.add('open'); btn.setAttribute('aria-expanded','true'); } 459 return; 460 } 461 if(!e.target.closest('[data-language-menu]')) closeLanguageMenus(); 462 }, true); 463 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeLanguageMenus(); }); 464})(); 465 466/* gerçek canlı kullanıcı sayacı ve forum heartbeat */ 467(function(){ 468 function qs(sel){ return document.querySelector(sel); } 469 function qsa(sel){ return Array.prototype.slice.call(document.querySelectorAll(sel)); } 470 function csrfToken(){ 471 var bodyToken = document.body ? (document.body.getAttribute('data-csrf-token') || '') : ''; 472 if(bodyToken) return bodyToken; 473 var meta = qs('meta[name="csrf-token"]'); 474 if(meta && meta.content) return meta.content; 475 var input = qs('input[name="_csrf"], input[name="csrf_token"], input[name="csrf"]'); 476 return input ? input.value : ''; 477 } 478 function postForm(url, data, useBeacon){ 479 if(!url) return; 480 var fd = new FormData();
481 Object.keys(data || {}).forEach(function(k){ fd.append(k, data[k]); }); 482 var token = csrfToken(); 483 if(token && !fd.has('_csrf')) fd.append('_csrf', token); 484 if(useBeacon && navigator.sendBeacon){ 485 try { navigator.sendBeacon(url, fd); return; } catch(e) {} 486 } 487 try { 488 fetch(url, {method:'POST', body:fd, credentials:'same-origin', keepalive:!!useBeacon, cache:'no-store'}).catch(function(){}); 489 } catch(e) {} 490 } 491 function currentForumId(){ 492 var node = qs('[data-current-forum-id]'); 493 if(!node) return 0; 494 var id = parseInt(node.getAttribute('data-current-forum-id') || node.dataset.currentForumId || '0', 10); 495 return isNaN(id) ? 0 : id; 496 } 497 function heartbeat(){ 498 var url = document.body.getAttribute('data-live-heartbeat-url'); 499 var forumId = currentForumId(); 500 if(url && forumId > 0){ postForm(url, {forum_id:String(forumId)}, false); } 501 } 502 function leaveForum(){ 503 var url = document.body.getAttribute('data-live-leave-url'); 504 var forumId = currentForumId(); 505 if(url && forumId > 0){ postForm(url, {forum_id:String(forumId)}, true); } 506 } 507 function refreshCounts(){ 508 var url = document.body.getAttribute('data-live-counts-url'); 509 var nodes = qsa('[data-forum-live-count]'); 510 if(!url || !nodes.length) return; 511 var ids = []; 512 nodes.forEach(function(node){ 513 var id = parseInt(node.getAttribute('data-forum-id') || '0', 10); 514 if(id > 0 && ids.indexOf(id) === -1) ids.push(id); 515 }); 516 if(!ids.length) return; 517 try { 518 fetch(url + '?ids=' + encodeURIComponent(ids.join(',')), {credentials:'same-origin', cache:'no-store'}) 519 .then(function(r){ return r.ok ? r.json() : null; }) 520 .then(function(payload){ 521 if(!payload || !payload.counts) return; 522 nodes.forEach(function(node){ 523 var id = node.getAttribute('data-forum-id'); 524 var count = payload.counts[id]; 525 if(typeof count === 'undefined') return; 526 var valueNode = node.querySelector('[data-live-count-value]'); 527 if(valueNode) valueNode.textContent = String(parseInt(count, 10) || 0); 528 }); 529 }).catch(function(){}); 530 } catch(e) {} 531 } 532 document.addEventListener('DOMContentLoaded', function(){ 533 heartbeat(); 534 refreshCounts(); 535 window.setTimeout(refreshCounts, 700); 536 if(currentForumId() > 0){ window.setInterval(function(){ heartbeat(); window.setTimeout(refreshCounts, 700); }, 12000); } 537 if(qsa('[data-forum-live-count]').length){ window.setInterval(refreshCounts, 8000); } 538 }); 539 window.addEventListener('wmt:live-refresh-request', refreshCounts); 540 window.addEventListener('pagehide', function(){ 541 if(currentForumId() > 0) leaveForum(); 542 }); 543 window.addEventListener('beforeunload', function(){ 544 if(currentForumId() > 0) leaveForum(); 545 }); 546})(); 547 548 549/* hızlı konu açma modalı + flat forum editörü */ 550(function(){ 551 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx||document).querySelectorAll(sel)); } 552 function qs(sel, ctx){ return (ctx||document).querySelector(sel); } 553 function openQuickTopic(){ var modal=qs('[data-quick-topic-modal]'); if(!modal) return; modal.hidden=false; modal.setAttribute('aria-hidden','false'); document.body.classList.add('quick-topic-opened'); setQuickTopicViewport(); var first=qs('input[name="title"]', modal); var isMobile=window.matchMedia && window.matchMedia('(max-width: 760px)').matches; if(first && !isMobile) setTimeout(function(){first.focus();},40); } 554 function closeQuickTopic(){ var modal=qs('[data-quick-topic-modal]'); if(!modal) return; modal.hidden=true; modal.setAttribute('aria-hidden','true'); document.body.classList.remove('quick-topic-opened'); } 555 556 function setQuickTopicViewport(){ 557 var h = (window.visualViewport && window.visualViewport.height) ? window.visualViewport.height : window.innerHeight; 558 document.documentElement.style.setProperty('--quick-topic-vh', Math.max(360, Math.floor(h || 0)) + 'px'); 559 } 560 window.addEventListener('resize', setQuickTopicViewport, {passive:true});
561 if(window.visualViewport) window.visualViewport.addEventListener('resize', setQuickTopicViewport, {passive:true}); 562 563 function syncTopicPrefixes(form){ 564 if(!form) return; 565 var forumSelect=qs('[data-new-topic-forum],[data-quick-topic-forum]', form); 566 var prefixSelect=qs('[data-topic-prefix-select]', form); 567 if(!forumSelect || !prefixSelect) return; 568 var field=prefixSelect.closest('[data-topic-prefix-field]'); 569 var forumId=String(forumSelect.value || ''); 570 var selectedAllowed=true, visibleCount=0; 571 qsa('option', prefixSelect).forEach(function(opt){ 572 if(!opt.value || opt.value === '0'){ opt.hidden=false; opt.disabled=false; return; } 573 var forums=(opt.getAttribute('data-forums') || '').split(',').map(function(v){ return v.trim(); }).filter(Boolean); 574 var allowed=(forums.indexOf(forumId) !== -1); 575 opt.hidden=!allowed; opt.disabled=!allowed; 576 if(allowed) visibleCount++; 577 if(opt.selected && !allowed) selectedAllowed=false; 578 }); 579 if(!selectedAllowed || visibleCount === 0) prefixSelect.value='0'; 580 if(field) field.hidden = visibleCount === 0; 581 } 582 function normalizeSitePromotionText(value){ 583 return String(value || '') 584 .replace(/\r\n?/g,'\n') 585 .replace(/<[^>]+>/g,' ') 586 .replace(/\[(?:\/?b|\/?strong)\]/gi,'') 587 .toLocaleLowerCase('tr-TR') 588 .replace(/ı/g,'i').replace(/ö/g,'o').replace(/ü/g,'u').replace(/Ä/g,'g').replace(/Å/g,'s').replace(/ç/g,'c') 589 .replace(/[ \t]+/g,' ') 590 .trim(); 591 } 592 function getSitePromotionField(form, name){ 593 var field=form ? qs('[data-site-promotion-field="'+name+'"]', form) : null; 594 return field ? String(field.value || '').trim() : ''; 595 } 596 function normalizeSitePromotionDomain(value){ 597 var raw=String(value || '').trim(); 598 if(!raw || raw.indexOf('\\') !== -1 || /^\/\//.test(raw)) return null; 599 if(!/^https?:\/\//i.test(raw)) raw='https://'+raw.replace(/^\/+/, ''); 600 try{ 601 var parsed=new URL(raw); 602 if(!/^https?:$/.test(parsed.protocol) || parsed.username || parsed.password || parsed.port || parsed.search || parsed.hash) return null; 603 if(parsed.pathname && parsed.pathname !== '/') return null; 604 var host=String(parsed.hostname || '').toLowerCase().replace(/\.$/, ''); 605 if(!host || host.indexOf('.') === -1 || /^\d{1,3}(?:\.\d{1,3}){3}$/.test(host)) return null; 606 return {url:parsed.protocol+'//'+host, domain:host.replace(/^www\./i,'')}; 607 }catch(err){ return null; } 608 } 609 function sitePromotionTextContainsDomain(text, domain){ 610 text=String(text || '').toLowerCase(); 611 domain=String(domain || '').toLowerCase().replace(/^www\./,''); 612 if(!text || !domain) return false; 613 var escaped=domain.replace(/[.*+?^${}()|[\]\\]/g,'\\$&'); 614 return new RegExp('(^|[^a-z0-9.-])(?:https?:\\/\\/)?(?:www\\.)?'+escaped+'(?=$|[^a-z0-9.-])','i').test(text); 615 } 616 function buildSitePromotionBody(form){ 617 if(!form) return ''; 618 var name=getSitePromotionField(form,'name'); 619 var url=getSitePromotionField(form,'url'); 620 var domainInfo=normalizeSitePromotionDomain(url); 621 if(domainInfo) url=domainInfo.url; 622 var topic=getSitePromotionField(form,'topic'); 623 var audience=getSitePromotionField(form,'audience'); 624 var reason=getSitePromotionField(form,'reason'); 625 var description=getSitePromotionField(form,'description'); 626 var social=getSitePromotionField(form,'social'); 627 var notes=getSitePromotionField(form,'notes'); 628 return '[b]Site Adı:[/b] '+(name || 'Belirtilmedi')+'\n'+ 629 '[b]Site Adresi:[/b] '+(url || 'Belirtilmedi')+'\n'+ 630 '[b]Site Konusu:[/b] '+(topic || 'Belirtilmedi')+'\n'+ 631 '[b]Hedef Kitle:[/b] '+(audience || 'Belirtilmedi')+'\n'+ 632 '[b]Neden Ziyaret Edilmeli?:[/b] '+(reason || 'Belirtilmedi')+'\n'+ 633 '[b]Tanıtım Yazısı:[/b] '+(description || 'Belirtilmedi')+'\n'+ 634 '[b]Sosyal Medya / İletiÅim:[/b] '+(social || 'Belirtilmedi')+'\n'+ 635 '[b]Ek Notlar:[/b] '+(notes || 'Yok'); 636 } 637 function writeSitePromotionBody(form){ 638 if(!form) return; 639 var textarea=qs('textarea[name="body"]', form); 640 if(!textarea) return; 641 textarea.value=buildSitePromotionBody(form); 642 textarea.setAttribute('data-site-promotion-template-applied','1'); 643 textarea.dispatchEvent(new Event('input',{bubbles:true})); 644 } 645 function sitePromotionBuilderError(form){ 646 if(!form) return 'Site Tanıtım formu bulunamadı.'; 647 var required=[ 648 ['title','Konu BaÅlıÄı alanını doldurun.'],
649 ['name','Site Adı alanını doldurun.'], 650 ['url','Domain Adı alanını doldurun. Ãrnek: siteadresiniz.com'], 651 ['topic','Site Konusu alanına sitenizin ne hakkında olduÄunu yazın.'], 652 ['audience','Hedef Kitle alanına sitenizin kimlere hitap ettiÄini yazın.'], 653 ['reason','Neden Ziyaret Edilmeli alanına açıklama yazın.'], 654 ['description','Tanıtım Yazısı alanına kısa açıklama yazın.'] 655 ]; 656 for(var i=0;i<required.length;i++){ 657 if(!getSitePromotionField(form, required[i][0])) return required[i][1]; 658 } 659 var title=getSitePromotionField(form,'title'); 660 if(title.length < 4) return 'Konu BaÅlıÄı en az 4 karakter olmalı.'; 661 var url=getSitePromotionField(form,'url'); 662 var domainInfo=normalizeSitePromotionDomain(url); 663 if(!domainInfo) return 'Domain Adı alanına yalnızca ana domaini yazın. Ãrnek: siteadresiniz.com. /sayfa, ?parametre, #alan ve özel port kabul edilmez.'; 664 var urlField=qs('[data-site-promotion-field="url"]', form); 665 if(urlField) urlField.value=domainInfo.url; 666 var domainFields=[ 667 ['title','Konu BaÅlıÄı'],['name','Site Adı'],['topic','Site Konusu'],['audience','Hedef Kitle'], 668 ['reason','Neden Ziyaret Edilmeli'],['description','Tanıtım Yazısı'],['social','Sosyal Medya / İletiÅim'],['notes','Ek Notlar'] 669 ]; 670 for(var d=0;d<domainFields.length;d++){ 671 if(sitePromotionTextContainsDomain(getSitePromotionField(form,domainFields[d][0]),domainInfo.domain)){ 672 return 'Domain adını yalnızca Domain Adı alanına yazın. '+domainFields[d][1]+' alanında '+domainInfo.domain+' tekrar kullanılamaz; /sayfa gibi uzantılar da eklenemez.'; 673 } 674 } 675 writeSitePromotionBody(form); 676 return ''; 677 } 678 function sitePromotionError(textarea){ 679 var raw=String((textarea && textarea.value) || ''); 680 var value=normalizeSitePromotionText(raw); 681 var labels=[ 682 ['site adi:', 'Site Adı'], 683 ['site adresi:', 'Site Adresi'], 684 ['site konusu:', 'Site Konusu'], 685 ['hedef kitle:', 'Hedef Kitle'], 686 ['neden ziyaret edilmeli?:', 'Neden Ziyaret Edilmeli?'], 687 ['tanitim yazisi:', 'Tanıtım Yazısı'], 688 ['sosyal medya / iletisim:', 'Sosyal Medya / İletiÅim'], 689 ['ek notlar:', 'Ek Notlar'] 690 ]; 691 var last=-1; 692 for(var i=0;i<labels.length;i++){ 693 var pos=value.indexOf(labels[i][0]); 694 if(pos === -1) return 'Site Tanıtım Åablonundaki "'+labels[i][1]+'" baÅlıÄı silinmiÅ veya deÄiÅtirilmiÅ. Alanları üstteki Site Tanıtım Formu üzerinden doldurun.'; 695 if(pos <= last) return 'Site Tanıtım Åablonunun sırası deÄiÅtirilmiÅ. Åablon baÅlıklarını silmeyin; alanları üstteki Site Tanıtım Formu üzerinden doldurun.'; 696 last=pos; 697 } 698 if(!/https?:\/\/[a-z0-9][^\s\]\[<>"]+/i.test(raw)) return 'Site Adresi bölümüne geçerli bir http/https baÄlantısı yazmalısınız.'; 699 var cleaned=value.replace(/site adi:|site adresi:|site konusu:|hedef kitle:|neden ziyaret edilmeli\?:|tanitim yazisi:|sosyal medya \/ iletisim:|ek notlar:/g,'').replace(/[-â¢\s]/g,''); 700 if(cleaned.length < 60) return 'Site Tanıtım yazısı çok kısa. Site Konusu, Hedef Kitle ve Neden Ziyaret Edilmeli alanlarını kısa ama anlaÅılır Åekilde doldurun.'; 701 return ''; 702 } 703 function setFieldsDisabled(root, disabled){ 704 if(!root) return; 705 qsa('input,textarea,select,button', root).forEach(function(field){ 706 if(field.matches('[data-site-promotion-use-template]')) return; 707 field.disabled = !!disabled; 708 }); 709 } 710 function syncSitePromotionTemplate(form, select){ 711 if(!form || !select) return; 712 var opt=select.options[select.selectedIndex]; 713 var isSitePromotion=!!(opt && opt.getAttribute('data-site-promotion') === '1'); 714 var card=qs('[data-site-promotion-template-card]', form); 715 if(card){ 716 card.hidden=!isSitePromotion; 717 card.classList.toggle('is-visible', isSitePromotion); 718 setFieldsDisabled(card, !isSitePromotion); 719 } 720 var webmaster=qs('[data-webmaster-topic-assistant]', form); 721 if(webmaster){ 722 webmaster.hidden = isSitePromotion; 723 if(isSitePromotion){ 724 webmaster.open = false;
725 qsa('input,select,textarea', webmaster).forEach(function(field){ 726 if(field.tagName === 'SELECT') field.selectedIndex = 0; 727 else field.value = ''; 728 }); 729 } 730 } 731 var normalTitle=qs('[data-normal-title-field]', form); 732 var bodyField=qs('[data-topic-body-field]', form); 733 var normalTags=qs('[data-normal-tags-field]', form); 734 [normalTitle, bodyField, normalTags].forEach(function(box){ 735 if(!box) return; 736 box.hidden = isSitePromotion; 737 setFieldsDisabled(box, isSitePromotion); 738 box.setAttribute('aria-hidden', isSitePromotion ? 'true' : 'false'); 739 }); 740 qsa('[data-site-promotion-submit]', form).forEach(function(btn){ 741 btn.textContent = isSitePromotion ? 'Site Ekle' : (form.matches('[data-quick-topic-form]') ? 'â Konuyu Aç' : 'Konuyu Aç'); 742 }); 743 var textarea=qs('textarea[name="body"]', form); 744 if(textarea){ 745 if(isSitePromotion){ 746 textarea.value=buildSitePromotionBody(form); 747 textarea.setAttribute('data-site-promotion-template-applied','1'); 748 textarea.dispatchEvent(new Event('input',{bubbles:true})); 749 } else { 750 textarea.removeAttribute('data-site-promotion-template-applied'); 751 } 752 } 753 qsa('[data-site-promotion-rich-editor]', form).forEach(function(box){ box.hidden = !isSitePromotion; }); 754 form.classList.toggle('is-site-promotion-topic', isSitePromotion); 755 } 756 function applySitePromotionTemplate(btn){ 757 var form=btn.closest('form'); if(!form) return; 758 writeSitePromotionBody(form); 759 var firstEmpty=qsa('[data-site-promotion-field]', form).filter(function(field){ return !field.disabled && !String(field.value || '').trim(); })[0]; 760 if(firstEmpty) firstEmpty.focus(); 761 } 762 function syncTopicForm(form, select){ if(!form || !select) return; var opt=select.options[select.selectedIndex]; var action=opt ? opt.getAttribute('data-action') : ''; if(action) form.setAttribute('action', action); syncTopicPrefixes(form); syncSitePromotionTemplate(form, select); } 763 function countText(textarea){ 764 var box=textarea.closest('[data-ffp-editor]'); if(!box) return; 765 var out=qs('[data-editor-count]', box); if(!out) return; 766 var text=textarea.value || ''; 767 var words=(text.trim().match(/\S+/g)||[]).length; 768 out.textContent=text.length+' karakter · '+words+' kelime'; 769 } 770 function wrapSelection(textarea, before, after, placeholder){ 771 textarea.focus(); 772 var start=textarea.selectionStart || 0, end=textarea.selectionEnd || 0; 773 var value=textarea.value || ''; 774 var selected=value.substring(start,end) || placeholder || ''; 775 var replacement=before+selected+after; 776 textarea.value=value.substring(0,start)+replacement+value.substring(end); 777 var pos=start+before.length+selected.length; 778 textarea.setSelectionRange(pos,pos); 779 textarea.dispatchEvent(new Event('input',{bubbles:true})); 780 } 781 function editorCommand(btn){ 782 var editor=btn.closest('[data-ffp-editor]'); if(!editor) return; 783 var textarea=qs('textarea', editor); if(!textarea) return; 784 var cmd=btn.getAttribute('data-editor-cmd'); 785 if(cmd==='bold') wrapSelection(textarea,'[b]','[/b]','kalın yazı'); 786 else if(cmd==='italic') wrapSelection(textarea,'[i]','[/i]','italik yazı'); 787 else if(cmd==='quote') wrapSelection(textarea,'[quote]\n','\n[/quote]','alıntı metni'); 788 else if(cmd==='code'){ 789 var start=textarea.selectionStart || 0, end=textarea.selectionEnd || 0, value=textarea.value || ''; 790 var selected=value.substring(start,end); 791 if(selected){ wrapSelection(textarea,'[code]\n','\n[/code]','kod'); } 792 else { wrapSelection(textarea,'[code]\n','\n[/code]','buraya kodu yapıÅtırın'); } 793 } 794 else if(cmd==='list') wrapSelection(textarea,'','', '- madde 1\n- madde 2'); 795 else if(cmd==='link'){ 796 var url=window.prompt('BaÄlantı adresi:', 'https://'); 797 if(!url) return; 798 if(!/^https?:\/\//i.test(url)) url='https://'+url; 799 wrapSelection(textarea,'[url='+url+']','[/url]','baÄlantı metni'); 800 } 801 } 802 document.addEventListener('click', function(e){ 803 var open=e.target.closest('[data-quick-topic-open]'); 804 if(open){ e.preventDefault(); openQuickTopic(); return; } 805 if(e.target.closest('[data-quick-topic-close]')){ e.preventDefault(); closeQuickTopic(); return; } 806 var promoTpl=e.target.closest('[data-site-promotion-use-template]'); 807 if(promoTpl){ e.preventDefault(); applySitePromotionTemplate(promoTpl); return; } 808 var cmd=e.target.closest('[data-editor-cmd]'); 809 if(cmd){ e.preventDefault(); editorCommand(cmd); return; } 810 var preset=e.target.closest('[data-prefix-preset]'); 811 if(preset){ 812 e.preventDefault(); 813 var form=preset.closest('form'); if(!form) return; 814 var bg=qs('input[name="bg_color"]', form), text=qs('input[name="text_color"]', form), border=qs('input[name="border_color"]', form); 815 if(bg) bg.value=preset.getAttribute('data-bg') || bg.value; 816 if(text) text.value=preset.getAttribute('data-text') || text.value; 817 if(border) border.value=preset.getAttribute('data-border') || border.value; 818 return; 819 } 820 }); 821 document.addEventListener('change', function(e){ 822 var sel=e.target.closest('[data-quick-topic-forum]'); 823 if(sel){ syncTopicForm(sel.closest('[data-quick-topic-form]'), sel); return; } 824 var sel2=e.target.closest('[data-new-topic-forum]'); 825 if(sel2){ syncTopicForm(sel2.closest('[data-new-topic-form]'), sel2); return; } 826 }); 827 document.addEventListener('input', function(e){ 828 var promoField=e.target.closest('[data-site-promotion-field]'); 829 if(promoField){ writeSitePromotionBody(promoField.closest('form')); if(e.target.matches('textarea')) countText(e.target); return; } 830 if(e.target.matches('[data-ffp-editor] textarea')) countText(e.target); 831 }); 832 document.addEventListener('submit', function(e){ 833 var form=e.target && (e.target.closest('[data-new-topic-form]') || e.target.closest('[data-quick-topic-form]')); 834 if(!form || !form.classList.contains('is-site-promotion-topic')) return; 835 writeSitePromotionBody(form); 836 var builderError=sitePromotionBuilderError(form); 837 if(builderError){ 838 e.preventDefault(); 839 alert(builderError);
840 var firstEmpty=qsa('[data-site-promotion-field]', form).filter(function(field){ return !field.disabled && !String(field.value || '').trim(); })[0]; 841 if(firstEmpty) firstEmpty.focus(); 842 } 843 }, true); 844 document.addEventListener('DOMContentLoaded', function(){ 845 qsa('[data-quick-topic-form]').forEach(function(form){ syncTopicForm(form, qs('[data-quick-topic-forum]', form)); }); 846 qsa('[data-new-topic-form]').forEach(function(form){ syncTopicForm(form, qs('[data-new-topic-forum]', form)); }); 847 qsa('[data-ffp-editor] textarea').forEach(countText); 848 }); 849 document.addEventListener('keydown', function(e){ if(e.key==='Escape') closeQuickTopic(); }); 850})(); 851 852/* yönetim kullanıcı uyarı modalı */ 853(function(){ 854 function qs(sel){ return document.querySelector(sel); } 855 function openWarn(btn){ 856 var modal = qs('[data-admin-warn-modal]'); 857 if(!modal) return; 858 var id = btn.getAttribute('data-user-id') || ''; 859 var username = btn.getAttribute('data-username') || 'Kullanıcı'; 860 var input = modal.querySelector('[data-admin-warn-user-id]'); 861 var title = modal.querySelector('[data-admin-warn-username]'); 862 if(input) input.value = id; 863 if(title) title.textContent = username; 864 modal.hidden = false; 865 document.body.classList.add('admin-warn-open'); 866 setTimeout(function(){ var ta = modal.querySelector('textarea[name="reason"]'); if(ta) ta.focus(); }, 50); 867 } 868 function closeWarn(){ 869 var modal = qs('[data-admin-warn-modal]'); 870 if(!modal) return; 871 modal.hidden = true; 872 document.body.classList.remove('admin-warn-open'); 873 } 874 document.addEventListener('click', function(e){ 875 var open = e.target.closest('[data-admin-warn-open]'); 876 if(open){ e.preventDefault(); openWarn(open); return; } 877 if(e.target.closest('[data-admin-warn-close]')){ e.preventDefault(); closeWarn(); return; } 878 }); 879 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeWarn(); }); 880})(); 881 882/* geliÅmiÅ resim yöneticisi ayrı pencere + görünür gönder butonları */ 883(function(){ 884 function qs(sel, ctx){ return (ctx||document).querySelector(sel); } 885 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx||document).querySelectorAll(sel)); } 886 function pageBody(){ return document.body || document.documentElement; } 887 var activeEditor = null; 888 var selectedImage = null; 889 890 function escapeHtml(value){ 891 return String(value == null ? '' : value).replace(/[&<>"']/g, function(ch){ return ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]); }); 892 } 893 function humanSize(bytes){ 894 bytes = parseInt(bytes || 0, 10) || 0; 895 if(bytes >= 1048576) return (bytes / 1048576).toFixed(1).replace('.0','') + ' MB'; 896 if(bytes >= 1024) return Math.round(bytes / 1024) + ' KB'; 897 return bytes ? (bytes + ' B') : ''; 898 } 899 function insertAtCursor(textarea, text){ 900 if(!textarea) return; 901 textarea.focus(); 902 var start = textarea.selectionStart || 0, end = textarea.selectionEnd || 0, val = textarea.value || ''; 903 var prefix = start > 0 && val.charAt(start-1) !== '\n' ? '\n' : ''; 904 var suffix = '\n'; 905 var insert = prefix + text + suffix; 906 textarea.value = val.substring(0,start) + insert + val.substring(end); 907 var pos = start + insert.length; 908 textarea.setSelectionRange(pos,pos); 909 textarea.dispatchEvent(new Event('input',{bubbles:true})); 910 } 911 function activeTextarea(){ return activeEditor ? qs('textarea', activeEditor) : null; } 912 913 function ensureImageButton(toolbar){ 914 if(!toolbar || toolbar.querySelector('[data-editor-image-open]')) return; 915 var btn = document.createElement('button'); 916 btn.type = 'button'; 917 btn.setAttribute('data-editor-image-open','1'); 918 btn.innerHTML = 'ð¼ï¸ Resim'; 919 toolbar.appendChild(btn); 920 } 921 922 function ensureModal(){ 923 var modal = qs('[data-editor-image-modal]'); 924 if(modal) return modal; 925 var fmt = pageBody().getAttribute('data-editor-default-format') || 'webp'; 926 var fmtLabel = (fmt || 'webp').toUpperCase(); 927 if(fmt === 'original') fmtLabel = 'ORİJİNAL'; 928 modal = document.createElement('div'); 929 modal.className = 'editor-image-modal'; 930 modal.setAttribute('data-editor-image-modal','1'); 931 modal.setAttribute('aria-hidden','true'); 932 modal.hidden = true; 933 modal.innerHTML = ''+ 934 '<div class="editor-image-modal-backdrop" data-editor-image-modal-close></div>'+ 935 '<section class="editor-image-window" role="dialog" aria-modal="true" aria-labelledby="editorImageWindowTitle">'+ 936 '<div class="editor-image-window-head">'+ 937 '<div><span class="eyebrow">Resim Yöneticisi</span><h2 id="editorImageWindowTitle">Resim</h2><p class="muted">Resim yükle, yazıya ekle veya kendi yüklediÄin resmi galeriden kaldır.</p></div>'+ 938 '<button type="button" class="editor-image-window-close" data-editor-image-modal-close aria-label="Kapat">â</button>'+ 939 '</div>'+ 940 '<div class="editor-image-manager-layout">'+ 941 '<aside class="editor-image-uploader">'+ 942 '<label class="editor-dropzone" data-editor-image-dropzone> '+ 943 '<input type="file" accept="image/png,image/jpeg,image/webp,image/gif" multiple data-editor-image-file>'+ 944 '<span class="drop-icon">â¬ï¸</span><strong>Resim seç veya buraya sürükle</strong><small>Yönetim ayarındaki format uygulanır: '+escapeHtml(fmtLabel)+'. Birden fazla resim seçebilirsin.<
944/small>'+ 945 '</label>'+ 946 '<div class="editor-selected-files" data-editor-selected-files>Henüz dosya seçilmedi.</div>'+ 947 '<div class="editor-image-window-actions">'+ 948 '<button type="button" class="btn primary" data-editor-image-upload-add>Yükle ve Yazıya Ekle</button>'+ 949 '<button type="button" class="btn" data-editor-image-upload-only>Yalnızca Yükle</button>'+ 950 '</div>'+ 951 '<div class="editor-image-status" data-editor-image-status></div>'+ 952 '</aside>'+ 953 '<main class="editor-image-library">'+ 954 '<div class="editor-image-library-head"><strong>Galeri</strong><button type="button" class="btn small" data-editor-image-refresh>Yenile</button></div>'+ 955 '<div class="editor-image-gallery-modal" data-editor-image-gallery><span class="muted">Galeri yükleniyor...</span></div>'+ 956 '</main>'+ 957 '</div>'+ 958 '<div class="editor-image-window-foot">'+ 959 '<div class="editor-image-selected" data-editor-image-selected>Galeriden bir resim seçip âYazıya Ekleâ diyebilirsin.</div>'+ 960 '<div class="editor-image-foot-actions"><button type="button" class="btn primary" data-editor-image-insert-selected disabled>Seçili Resmi Yazıya Ekle</button><button type="button" class="btn" data-editor-image-modal-close>Kapat</button></div>'+ 961 '</div>'+ 962 '</section>'; 963 pageBody().appendChild(modal); 964 return modal; 965 } 966 967 function setStatus(msg, type){ 968 var modal = ensureModal(); 969 var n = qs('[data-editor-image-status]', modal); 970 if(n){ n.textContent = msg || ''; n.className = 'editor-image-status ' + (type || ''); } 971 } 972 function setSelected(item){ 973 selectedImage = item || null; 974 var modal = ensureModal(); 975 qsa('.editor-image-card.is-selected', modal).forEach(function(card){ card.classList.remove('is-selected'); }); 976 if(item && item.id){ 977 var card = qs('[data-editor-image-id="'+String(item.id).replace(/"/g,'')+'"]', modal); 978 if(card) card.classList.add('is-selected'); 979 } 980 var out = qs('[data-editor-image-selected]', modal); 981 var btn = qs('[data-editor-image-insert-selected]', modal); 982 if(out) out.innerHTML = item ? ('<strong>'+escapeHtml(item.name || 'Resim')+'</strong><small>'+escapeHtml(item.meta || '')+'</small>') : 'Galeriden bir resim seçip âYazıya Ekleâ diyebilirsin.'; 983 if(btn) btn.disabled = !item; 984 } 985 function openModal(editor){ 986 activeEditor = editor; 987 selectedImage = null; 988 var modal = ensureModal(); 989 modal.hidden = false; 990 modal.setAttribute('aria-hidden','false'); 991 pageBody().classList.add('editor-image-modal-open'); 992 setSelected(null); 993 updateSelectedFiles(); 994 loadGallery(); 995 setTimeout(function(){ var input = qs('[data-editor-image-file]', modal); if(input) input.focus(); }, 40); 996 } 997 function closeModal(){ 998 var modal = qs('[data-editor-image-modal]'); 999 if(!modal) return; 1000 modal.hidden = true; 1001 modal.setAttribute('aria-hidden','true'); 1002 pageBody().classList.remove('editor-image-modal-open'); 1003 } 1004 1005 function updateSelectedFiles(){ 1006 var modal = ensureModal(); 1007 var input = qs('[data-editor-image-file]', modal); 1008 var out = qs('[data-editor-selected-files]', modal); 1009 if(!out || !input) return; 1010 var files = Array.prototype.slice.call(input.files || []); 1011 if(!files.length){ out.textContent = 'Henüz dosya seçilmedi.'; return; } 1012 out.innerHTML = files.map(function(file){ return '<span>ð¼ï¸ '+escapeHtml(file.name)+' <small>'+humanSize(file.size)+'</small></span>'; }).join(''); 1013 } 1014 1015 function loadGallery(){ 1016 var modal = ensureModal(); 1017 var url = pageBody().getAttribute('data-editor-images-url'); 1018 var gallery = qs('[data-editor-image-gallery]', modal); 1019 if(!url || !gallery) return; 1020 gallery.innerHTML = '<span class="muted">Galeri yükleniyor...</span>'; 1021 fetch(url, {credentials:'same-origin'}).then(function(r){ return r.json(); }).then(function(payload){ 1022 if(!payload || !payload.ok){ gallery.innerHTML = '<span class="muted">
1022Galeri yüklenemedi.</span>'; return; } 1023 var items = payload.items || []; 1024 if(!items.length){ gallery.innerHTML = '<span class="muted">Henüz yüklenmiÅ resim yok.</span>'; return; } 1025 gallery.innerHTML = items.map(function(item){ 1026 var name = item.name || 'Resim'; 1027 var dimensions = (item.width && item.height) ? (item.width + 'Ã' + item.height) : ''; 1028 var metaParts = []; 1029 if(dimensions) metaParts.push(dimensions); 1030 if(item.size_bytes) metaParts.push(humanSize(item.size_bytes)); 1031 if(item.user) metaParts.push('@' + item.user); 1032 var meta = metaParts.join(' · '); 1033 var del = item.can_delete ? '<button type="button" class="mini-danger" data-editor-image-delete="'+escapeHtml(item.id)+'">Kaldır</button>' : ''; 1034 return ''+ 1035 '<article class="editor-image-card" data-editor-image-id="'+escapeHtml(item.id)+'" data-editor-image-bbcode="'+escapeHtml(item.bbcode || '')+'" data-editor-image-name="'+escapeHtml(name)+'" data-editor-image-meta="'+escapeHtml(meta)+'">'+ 1036 '<button type="button" class="editor-image-preview" data-editor-image-select><img src="'+escapeHtml(item.url || '')+'" alt=""></button>'+ 1037 '<div class="editor-image-card-info"><strong>'+escapeHtml(name)+'</strong><small>'+escapeHtml(meta)+'</small></div>'+ 1038 '<div class="editor-image-card-actions"><button type="button" class="mini-primary" data-editor-image-add>Yazıya Ekle</button>'+del+'</div>'+ 1039 '</article>'; 1040 }).join(''); 1041 setSelected(null); 1042 }).catch(function(){ gallery.innerHTML = '<span class="muted">Galeri yüklenemedi.</span>'; }); 1043 } 1044 1045 function cardItem(card){ 1046 if(!card) return null; 1047 return { 1048 id: card.getAttribute('data-editor-image-id') || '', 1049 bbcode: card.getAttribute('data-editor-image-bbcode') || '', 1050 name: card.getAttribute('data-editor-image-name') || 'Resim', 1051 meta: card.getAttribute('data-editor-image-meta') || '' 1052 }; 1053 } 1054 function insertImage(item){ 1055 if(!item || !item.bbcode){ setStatus('Eklenecek resim seçilmedi.', 'error'); return; } 1056 insertAtCursor(activeTextarea(), item.bbcode); 1057 setStatus('Resim yazıya eklendi. Gönder/Cevapla butonu altta görünür kalır.', 'success'); 1058 } 1059 1060 function uploadFiles(insertAfterUpload){ 1061 var modal = ensureModal(); 1062 var uploadUrl = pageBody().getAttribute('data-editor-upload-url'); 1063 var token = pageBody().getAttribute('data-csrf-token') || ''; 1064 var input = qs('[data-editor-image-file]', modal); 1065 var files = input ? Array.prototype.slice.call(input.files || []) : []; 1066 if(!uploadUrl || !files.length){ setStatus('Yüklenecek resmi seçin.', 'error'); return; } 1067 var done = 0, added = 0; 1068 setStatus(files.length + ' resim optimize edilip yükleniyor...', 'loading'); 1069 function next(){ 1070 if(!files.length){
1071 setStatus(done + ' resim yüklendi' + (added ? ' ve yazıya eklendi.' : '.'), 'success'); 1072 if(input) input.value = ''; 1073 updateSelectedFiles(); 1074 loadGallery(); 1075 return; 1076 } 1077 var file = files.shift(); 1078 var fd = new FormData(); 1079 fd.append('_csrf', token); 1080 fd.append('image', file); 1081 fetch(uploadUrl, {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){ 1082 return r.json().catch(function(){ return {ok:false,message:'Sunucu yanıtı okunamadı.'}; }); 1083 }).then(function(payload){ 1084 if(!payload || !payload.ok){ throw new Error((payload && payload.message) ? payload.message : 'Resim yüklenemedi.'); } 1085 done++; 1086 if(insertAfterUpload && payload.bbcode){ insertAtCursor(activeTextarea(), payload.bbcode); added++; } 1087 next(); 1088 }).catch(function(err){ 1089 setStatus((err && err.message) ? err.message : 'Resim yüklenemedi.', 'error'); 1090 }); 1091 } 1092 next(); 1093 } 1094 1095 function deleteImage(id){ 1096 var deleteUrl = pageBody().getAttribute('data-editor-delete-url'); 1097 var token = pageBody().getAttribute('data-csrf-token') || ''; 1098 if(!deleteUrl || !id) return; 1099 if(!window.confirm('Bu resmi galeriden kaldırmak istiyor musunuz?')) return; 1100 var fd = new FormData(); 1101 fd.append('_csrf', token); 1102 fd.append('id', id); 1103 setStatus('Resim kaldırılıyor...', 'loading'); 1104 fetch(deleteUrl, {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){ return r.json().catch(function(){ return {ok:false,message:'Sunucu yanıtı okunamadı.'}; }); }).then(function(payload){ 1105 if(!payload || !payload.ok){ setStatus((payload && payload.message) ? payload.message : 'Resim kaldırılamadı.', 'error'); return; } 1106 setStatus(payload.message || 'Resim kaldırıldı.', 'success'); 1107 setSelected(null); 1108 loadGallery(); 1109 }).catch(function(){ setStatus('Resim kaldırılamadı.', 'error'); }); 1110 } 1111 1112 document.addEventListener('DOMContentLoaded', function(){ 1113 qsa('[data-ffp-editor] .ffp-editor-toolbar').forEach(ensureImageButton); 1114 }); 1115 document.addEventListener('click', function(e){ 1116 var open = e.target.closest('[data-editor-image-open]'); 1117 if(open){ e.preventDefault(); var ed = open.closest('[data-ffp-editor]'); if(ed) openModal(ed); return; } 1118 if(e.target.closest('[data-editor-image-modal-close]')){ e.preventDefault(); closeModal(); return; } 1119 if(e.target.closest('[data-editor-image-refresh]')){ e.preventDefault(); loadGallery(); return; } 1120 if(e.target.closest('[data-editor-image-upload-add]')){ e.preventDefault(); uploadFiles(true); return; } 1121 if(e.target.closest('[data-editor-image-upload-only]')){ e.preventDefault(); uploadFiles(false); return; } 1122 var card = e.target.closest('.editor-image-card'); 1123 if(e.target.closest('[data-editor-image-select]') && card){ e.preventDefault(); setSelected(cardItem(card)); return; } 1124 if(e.target.closest('[data-editor-image-add]') && card){ e.preventDefault(); var item = cardItem(card); setSelected(item); insertImage(item); return; } 1125 var del = e.target.closest('[data-editor-image-delete]'); 1126 if(del){ e.preventDefault(); deleteImage(del.getAttribute('data-editor-image-delete')); return; } 1127 if(e.target.closest('[data-editor-image-insert-selected]')){ e.preventDefault(); insertImage(selectedImage); return; } 1128 }); 1129 document.addEventListener('change', function(e){ if(e.target.closest('[data-editor-image-file]')) updateSelectedFiles(); }); 1130 document.addEventListener('dragover', function(e){ 1131 var dz = e.target.closest('[data-editor-image-dropzone]'); 1132 if(!dz) return; 1133 e.preventDefault(); dz.classList.add('is-dragging'); 1134 }); 1135 document.addEventListener('dragleave', function(e){ 1136 var dz = e.target.closest('[data-editor-image-dropzone]'); 1137 if(dz) dz.classList.remove('is-dragging'); 1138 }); 1139 document.addEventListener('drop', function(e){ 1140 var dz = e.target.closest('[data-editor-image-dropzone]'); 1141 if(!dz) return; 1142 e.preventDefault(); dz.classList.remove('is-dragging'); 1143 var input = qs('[data-editor-image-file]', ensureModal()); 1144 if(input && e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length){ 1145 input.files = e.dataTransfer.files; 1146 updateSelectedFiles(); 1147 } 1148 }); 1149 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeModal(); }); 1150})(); 1151 1152/* forum editörüne flat deÄerlendirme, geliÅmiÅ renk penceresi ve araç pencereleri */ 1153(function(){ 1154 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx||document).querySelectorAll(sel)); } 1155 function qs(sel, ctx){ return (ctx||document).querySelector(sel); } 1156 function pageBody(){ return document.body || document.documentElement; } 1157 function esc(v){ return String(v == null ? '' : v).replace(/[&<>"']/g, function(ch){ return ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]); }); } 1158 function wrap(textarea, before, after, placeholder){ 1159 if(!textarea) return; textarea.focus(); 1160 var start=textarea.selectionStart||0,end=textarea.selectionEnd||0,val=textarea.value||''; 1161 var selected=val.substring(start,end)||placeholder||''; 1162 var rep=before+selected+after; textarea.value=val.substring(0,start)+rep+val.substring(end); 1163 var pos=start+before.length+selected.length; textarea.setSelectionRange(pos,pos); 1164 textarea.dispatchEvent(new Event('input',{bubbles:true})); 1165 } 1166 function cleanHeadingText(text){ 1167 text = String(text == null ? '' : text); 1168 text = text.replace(/^\s*\[h(?:[1-3])?\]\s*/i, '').replace(/\s*\[\/h(?:[1-3])?\]\s*$/i, ''); 1169 return text.replace(/^\n+|\n+$/g, '') || 'BaÅlık metni'; 1170 } 1171 function applyHeading(textarea, tag){ 1172 if(!textarea || !tag) return; 1173 textarea.focus(); 1174 var value = textarea.value || ''; 1175 var start = textarea.selectionStart || 0; 1176 var end = textarea.selectionEnd || 0; 1177 if(start === end){ 1178 var lineStart = value.lastIndexOf('\n', Math.max(0, start - 1)); 1179 lineStart = lineStart < 0 ? 0 : lineStart + 1; 1180 var lineEnd = value.indexOf('\n', start); 1181 lineEnd = lineEnd < 0 ? value.length : lineEnd; 1182 start = lineStart; 1183 end = lineEnd; 1184 } 1185 var selected = value.substring(start, end); 1186 var clean = cleanHeadingText(selected); 1187 var replacement = tag === 'normal' ? clean : '[' + tag + ']' + clean + '[/' + tag + ']'; 1188 textarea.value = value.substring(0, start) + replacement + value.substring(end); 1189 textarea.setSelectionRange(start, start + replacement.length); 1190 textarea.dispatchEvent(new Event('input', {bubbles:true})); 1191 } 1192 function insert(textarea, value){ 1193 if(!textarea) return; textarea.focus(); 1194 var start=textarea.selectionStart||0,end=textarea.selectionEnd||0,val=textarea.value||''; 1195 var prefix=start>0 && val.charAt(start-1)!=='\n' ? '\n' : ''; 1196 var text=prefix+value+(value.slice(-1)==='\n'?'':'\n'); 1197 textarea.value=val.substring(0,start)+text+val.substring(end); 1198 var pos=start+text.length; textarea.setSelectionRange(pos,pos); 1199 textarea.dispatchEvent(new Event('input',{bubbles:true})); 1200 } 1201 function selectedOrPlaceholder(textarea, placeholder){ 1202 if(!textarea) return placeholder || ''; 1203 var val=textarea.value||'', start=textarea.selectionStart||0, end=textarea.selectionEnd||0; 1204 return (val.substring(start,end)||placeholder||'').trim(); 1205 } 1206 function editorInsertGroup(toolbar){ 1207 var group=toolbar.querySelector('[data-editor-insert-group]'); 1208 if(group) return group; 1209 group=document.createElement('span'); 1210 group.className='ffp-editor-insert-group'; 1211 group.setAttribute('data-editor-insert-group','1'); 1212 group.innerHTML='';
1213 var img=toolbar.querySelector('[data-editor-image-open]'); 1214 toolbar.insertBefore(group, img || null); 1215 return group; 1216 } 1217 function editorToolShelf(editor){ 1218 var shelf=editor.querySelector('[data-editor-tool-shelf]'); 1219 if(shelf) return shelf; 1220 shelf=document.createElement('div'); 1221 shelf.className='ffp-editor-tool-shelf'; 1222 shelf.setAttribute('data-editor-tool-shelf','1'); 1223 shelf.innerHTML='<span class="ffp-editor-tool-shelf-title">İçerik kutuları</span>'; 1224 var toolbar=editor.querySelector('.ffp-editor-toolbar'); 1225 if(toolbar && toolbar.parentNode) toolbar.parentNode.insertBefore(shelf, toolbar.nextSibling); 1226 return shelf; 1227 } 1228 function add(toolbar, cmd, html, title, groupName){ 1229 if(toolbar.querySelector('[data-editor-advanced-cmd="'+cmd+'"]')) return; 1230 var b=document.createElement('button'); b.type='button'; b.setAttribute('data-editor-advanced-cmd',cmd); b.innerHTML=html; 1231 if(title){ b.title=title; b.setAttribute('aria-label', title); } 1232 if(groupName === 'insert') { editorInsertGroup(toolbar).appendChild(b); return; } 1233 var img=toolbar.querySelector('[data-editor-image-open]'); toolbar.insertBefore(b, img || null); 1234 } 1235 function addHeadingControl(toolbar){ 1236 if(!toolbar) return; 1237 var wrap = toolbar.querySelector('[data-editor-heading-select]'); 1238 if(wrap){ wrap = wrap.closest('.ffp-editor-heading-control'); } 1239 if(!wrap){ 1240 wrap = document.createElement('label'); 1241 wrap.className = 'ffp-editor-heading-control'; 1242 wrap.innerHTML = '<span>BaÅlık</span><select data-editor-heading-select aria-label="BaÅlık seviyesi seç"><option value="">Normal</option><option value="h1">BaÅlık 1</option><option value="h2">BaÅlık 2</option><option value="h3">BaÅlık 3</option><option value="normal">Normal yazı</option></select>'; 1243 } 1244 wrap.setAttribute('data-editor-heading-control','1'); 1245 /* BaÅlık seçimi araç çubuÄunun en baÅında kalır. */ 1246 toolbar.insertBefore(wrap, toolbar.firstElementChild || null); 1247 } 1248 function addShelf(editor, cmd, html, title){ 1249 if(!editor || editor.querySelector('[data-editor-advanced-cmd="'+cmd+'"]')) return; 1250 var b=document.createElement('button'); b.type='button'; b.className='ffp-editor-shelf-btn'; b.setAttribute('data-editor-advanced-cmd',cmd); b.innerHTML=html; 1251 if(title){ b.title=title; b.setAttribute('aria-label', title); } 1252 editorToolShelf(editor).appendChild(b); 1253 } 1254 function editorExternalTools(editor){ 1255 if(!editor) return null; 1256 if(editor.__ffpExternalTools) return editor.__ffpExternalTools; 1257 var wrap=document.createElement('div'); 1258 wrap.className='ffp-editor-content-addons'; 1259 wrap.setAttribute('data-editor-content-addons','1'); 1260 wrap.innerHTML='<div class="ffp-editor-content-addons-head"><span>İlk Mesaj DeÄerlendirmesi</span><small>DeÄerlendirme kutusu sadece konu açarken ilk yazıya eklenir.</small></div><div class="ffp-editor-content-addons-actions"></div>'; 1261 wrap.__ffpEditor = editor; 1262 if(editor.parentNode) editor.parentNode.insertBefore(wrap, editor.nextSibling); 1263 editor.__ffpExternalTools = wrap; 1264 return wrap; 1265 } 1266 function addExternalTool(editor, cmd, html, title){ 1267 var wrap = editorExternalTools(editor); if(!wrap) return; 1268 if(wrap.querySelector('[data-editor-external-cmd="'+cmd+'"]')) return; 1269 var actions = wrap.querySelector('.ffp-editor-content-addons-actions') || wrap; 1270 var b=document.createElement('button'); b.type='button'; b.className='ffp-editor-content-addon-btn'; b.setAttribute('data-editor-external-cmd',cmd); b.innerHTML=html; 1271 if(title){ b.title=title; b.setAttribute('aria-label', title); } 1272 actions.appendChild(b); 1273 } 1274 function normalizeBaseToolbar(tb){ 1275 var names={bold:'Kalın',italic:'İtalik',quote:'Alıntı',code:'Kod',link:'BaÄlantı',list:'Liste'}; 1276 qsa('[data-editor-cmd]', tb).forEach(function(btn){ 1277 var cmd=btn.getAttribute('data-editor-cmd')||''; 1278 if(names[cmd]){ btn.title=names[cmd]; btn.setAttribute('aria-label', names[cmd]); btn.classList.add('ffp-tool-'+cmd); } 1279 }); 1280 }
1281 function init(){ 1282 qsa('[data-ffp-editor] .ffp-editor-toolbar').forEach(function(tb){ 1283 var editor=tb.closest('[data-ffp-editor]'); 1284 if(editor) editor.classList.add('ffp-editor-r10-flat'); 1285 tb.classList.add('ffp-toolbar-compact'); 1286 normalizeBaseToolbar(tb); 1287 addHeadingControl(tb); 1288 add(tb,'underline','<u>U</u>','Altı çizili'); 1289 add(tb,'strike','<s>S</s>','Ãstü çizili'); 1290 add(tb,'center','â Orta','Ortala'); 1291 add(tb,'right','⦠SaÄ','SaÄa hizala'); 1292 add(tb,'spoiler','ð Gizli','Gizli metin/spoiler'); 1293 add(tb,'hr','â Ãizgi','Ayırıcı çizgi'); 1294 add(tb,'color','ð¨ Renk','Renk penceresinden yazı rengi seç','insert'); 1295 if(editor && editor.hasAttribute('data-editor-rating-allowed')){ 1296 addExternalTool(editor,'rating','â DeÄerlendirme','İlk forum yazısına flat deÄerlendirme kutusu ekle'); 1297 } 1298 }); 1299 } 1300 1301 var activeTextarea = null; 1302 var activeReviewScore = 5; 1303 var palette = ['#111827','#334155','#64748b','#ef4444','#f97316','#f59e0b','#22c55e','#14b8a6','#06b6d4','#2563eb','#7c3aed','#db2777']; 1304 1305 function ensureToolModals(){ 1306 if(qs('[data-editor-color-modal]') && qs('[data-editor-rating-modal]')) return; 1307 var wrap=document.createElement('div'); 1308 wrap.innerHTML = ''+ 1309 '<div class="editor-tool-modal" data-editor-color-modal hidden aria-hidden="true">'+ 1310 '<div class="editor-tool-backdrop" data-editor-tool-close></div>'+ 1311 '<section class="editor-tool-window editor-color-window" role="dialog" aria-modal="true" aria-labelledby="editorColorTitle">'+ 1312 '<div class="editor-tool-head"><div><span class="eyebrow">Renk Seçimi</span><h2 id="editorColorTitle">Yazı rengini seç</h2><p class="muted">Penceredeki renge tıklayınca seçili yazıya uygulanır.</p></div><button type="button" class="editor-tool-close" data-editor-tool-close aria-label="Kapat">â</button></div>'+ 1313 '<div class="editor-color-grid" data-editor-color-grid></div>'+ 1314 '<div class="editor-color-custom"><label>Ãzel renk kodu<input type="text" data-editor-color-custom value="#2563eb" placeholder="#2563eb"></label><button type="button" class="btn primary small" data-editor-color-apply>Uygula</button></div>'+ 1315 '</section>'+ 1316 '</div>'+ 1317 '<div class="editor-tool-modal" data-editor-rating-modal hidden aria-hidden="true">'+ 1318 '<div class="editor-tool-backdrop" data-editor-tool-close></div>'+ 1319 '<section class="editor-tool-window editor-rating-window" role="dialog" aria-modal="true" aria-labelledby="editorRatingTitle">'+ 1320 '<div class="editor-tool-head"><div><span class="eyebrow">DeÄerlendirme</span><h2 id="editorRatingTitle">Yazıya deÄerlendirme ekle</h2><p class="muted">Puanı seç, baÅlık/metin yaz ve flat deÄerlendirme kutusunu yazıya ekle.</p></div><button type="button" class="editor-tool-close" data-editor-tool-close aria-label="Kapat">â</button></div>'+ 1321 '<div class="editor-rating-stars" data-editor-rating-stars></div>'+ 1322 '<div class="editor-rating-fields"><label>BaÅlık<input type="text" data-editor-rating-title placeholder="Ãrn: Genel deÄerlendirme"></label><label>Kısa açıklama<textarea rows="4" data-editor-rating-text placeholder="DeÄerlendirme metni..."></textarea></label></div>'+ 1323 '<div class="editor-tool-actions"><button type="button" class="btn" data-editor-tool-close>Vazgeç</button><button type="button" class="btn primary" data-editor-rating-insert>DeÄerlendirmeyi Yazıya Ekle</button></div>'+ 1324 '</section>'+ 1325 '</div>'; 1326 while(wrap.firstChild) pageBody().appendChild(wrap.firstChild); 1327 var grid=qs('[data-editor-color-grid]'); 1328 if(grid){ 1329 grid.innerHTML=palette.map(function(c){ return '<button type="button" class="editor-color-swatch" data-editor-color="'+esc(c)+'" style="--swatch:'+esc(c)+'"><span></span><strong>'+esc(c)+'</strong></button>'; }).join(''); 1330 } 1331 var stars=qs('[data-editor-rating-stars]'); 1332 if(stars){ 1333 stars.innerHTML=[1,2,3,4,5].map(function(n){ return '<button type="button" class="editor-rating-star '+(n===5?'is-active':'')+'" data-editor-rating-score="'+n+'" aria-pressed="'+(n===5?'true':'false')+'">'+('â â â â â '.slice(0,n))+'<small>'+n+'/5</small></button>'; }).join(''); 1334 } 1335 } 1336 function closeTools(){ 1337 qsa('.editor-tool-modal').forEach(function(m){ m.hidden=true; m.setAttribute('aria-hidden','true'); }); 1338 pageBody().classList.remove('editor-tool-opened'); 1339 } 1340 function openTool(name, textarea){ 1341 ensureToolModals(); activeTextarea = textarea; 1342 var modal = name==='rating' ? qs('[data-editor-rating-modal]') : qs('[data-editor-color-modal]'); 1343 if(!modal) return; 1344 modal.hidden=false; modal.setAttribute('aria-hidden','false'); pageBody().classList.add('editor-tool-opened'); 1345 setTimeout(function(){ var first=qs('input,textarea,button', modal); if(first) first.focus(); },40); 1346 } 1347 function applyColor(color){ 1348 color=(color||'').trim(); 1349 if(!/^#[0-9a-f]{3}([0-9a-f]{3})?$/i.test(color)){ alert('Lütfen #2563eb gibi geçerli renk kodu girin.'); return; } 1350 wrap(activeTextarea,'[color='+color+']','[/color]','renkli yazı'); 1351 closeTools(); 1352 } 1353 function setReviewScore(score){ 1354 activeReviewScore = Math.max(1, Math.min(5, parseInt(score||5,10)||5)); 1355 qsa('[data-editor-rating-score]').forEach(function(b){ 1356 var on=parseInt(b.getAttribute('data-editor-rating-score')||0,10)===activeReviewScore; 1357 b.classList.toggle('is-active', on); b.setAttribute('aria-pressed', on ? 'true' : 'false'); 1358 }); 1359 } 1360 function insertReview(){ 1361 var modal=qs('[data-editor-rating-modal]'); 1362 var title=(qs('[data-editor-rating-title]', modal)||{}).value || 'Genel deÄerlendirme'; 1363 var body=(qs('[data-editor-rating-text]', modal)||{}).value || selectedOrPlaceholder(activeTextarea, 'DeÄerlendirme metni'); 1364 var text='[rating='+activeReviewScore+']\n'+title.trim()+'\n'+body.trim()+'\n[/rating]'; 1365 insert(activeTextarea, text); 1366 var t=qs('[data-editor-rating-title]', modal), ta=qs('[data-editor-rating-text]', modal); 1367 if(t) t.value=''; if(ta) ta.value=''; setReviewScore(5); closeTools(); 1368 } 1369 document.addEventListener('DOMContentLoaded', function(){ init(); ensureToolModals(); }); 1370 document.addEventListener('change', function(e){ 1371 var select = e.target.closest('[data-editor-heading-select]'); 1372 if(!select) return; 1373 var editor = select.closest('[data-ffp-editor]'); 1374 var ta = editor ? qs('textarea', editor) : null; 1375 var tag = select.value || ''; 1376 if(tag) applyHeading(ta, tag); 1377 select.value = ''; 1378 }); 1379 document.addEventListener('click', function(e){ 1380 var b=e.target.closest('[data-editor-advanced-cmd],[data-editor-external-cmd]'); 1381 if(b){ 1382 e.preventDefault(); 1383 var addon=b.closest('[data-editor-content-addons]'); 1384 var editor=addon ? addon.__ffpEditor : b.closest('[data-ffp-editor]'); 1385 if(!editor) return; 1386 var ta=qs('textarea', editor), cmd=b.getAttribute('data-editor-advanced-cmd') || b.getAttribute('data-editor-external-cmd'); 1387 if(cmd==='underline') wrap(ta,'[u]','[/u]','altı çizili yazı'); 1388 if(cmd==='strike') wrap(ta,'[s]','[/s]','üstü çizili yazı'); 1389 if(cmd==='heading') applyHeading(ta,'h2'); 1390 if(cmd==='center') wrap(ta,'[center]','[/center]','ortalanmıŠyazı'); 1391 if(cmd==='right') wrap(ta,'[right]','[/right]','saÄa hizalı yazı'); 1392 if(cmd==='spoiler') wrap(ta,'[spoiler]','[/spoiler]','gizli metin'); 1393 if(cmd==='hr') insert(ta,'[hr]'); 1394 if(cmd==='color') openTool('color', ta); 1395 if(cmd==='rating') openTool('rating', ta); 1396 return; 1397 } 1398 var sw=e.target.closest('[data-editor-color]'); if(sw){ e.preventDefault(); applyColor(sw.getAttribute('data-editor-color')||''); return; } 1399 var apply=e.target.closest('[data-editor-color-apply]'); if(apply){ e.preventDefault(); applyColor((qs('[data-editor-color-custom]')||{}).value || ''); return; } 1400 var star=e.target.closest('[data-editor-rating-score]'); if(star){ e.preventDefault(); setReviewScore(star.getAttribute('data-editor-rating-score')); return; } 1401 var ins=e.target.closest('[data-editor-rating-insert]'); if(ins){ e.preventDefault(); insertReview(); return; } 1402 if(e.target.closest('[data-editor-tool-close]')){ e.preventDefault(); closeTools(); return; } 1403 }); 1404 document.addEventListener('keydown', function(e){ if(e.key==='Escape') closeTools(); }); 1405})(); 1406 1407/* forum yazısı düzenleme modalı + hızlı cevap odaklama */ 1408(function(){ 1409 function qs(sel, ctx){ return (ctx||document).querySelector(sel); } 1410 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx||document).querySelectorAll(sel)); } 1411 function body(){ return document.body || document.documentElement; } 1412 function openEdit(id){ 1413 var modal=document.getElementById(id); if(!modal) return null; 1414 /* Modal yazının/footerın içinde sıkıÅmasın diye açılırken body altına taÅınır. */ 1415 if(!modal.__ffpPlaceholder){ 1416 modal.__ffpPlaceholder=document.createComment('post-edit-modal-placeholder:'+id); 1417 if(modal.parentNode) modal.parentNode.insertBefore(modal.__ffpPlaceholder, modal); 1418 } 1419 if(modal.parentNode !== body()) body().appendChild(modal); 1420 modal.hidden=false; modal.setAttribute('aria-hidden','false'); body().classList.add('post-edit-opened'); 1421 setTimeout(function(){ var ta=qs('textarea', modal); if(ta){ ta.focus(); ta.setSelectionRange(ta.value.length, ta.value.length); } }, 50); 1422 return modal; 1423 } 1424 function prepareFirstPostRating(modal){ 1425 var ta=qs('textarea', modal); if(!ta) return; 1426 if(!/\[rating(?:=|\])/i.test(ta.value || '')){ 1427 var insert='\n\n[rating=5]\nGenel deÄerlendirme\nBu ilk forum yazısı için deÄerlendirme metnini buraya yazın.\n[/rating]'; 1428 ta.value=(ta.value || '').replace(/\s+$/,'') + insert; 1429 ta.dispatchEvent(new Event('input', {bubbles:true})); 1430 } 1431 setTimeout(function(){ 1432 ta.focus(); 1433 var pos=ta.value.length; 1434 ta.setSelectionRange(pos, pos); 1435 var note=qs('.post-edit-head .muted', modal); 1436 if(note) note.textContent='DeÄerlendirme alanı ilk yazıya eklendi. Metni düzenleyip kaydedebilirsiniz.'; 1437 }, 80); 1438 } 1439 function closeEdit(modal){ 1440 if(!modal) return; 1441 modal.hidden=true; modal.setAttribute('aria-hidden','true'); body().classList.remove('post-edit-opened'); 1442 if(modal.__ffpPlaceholder && modal.__ffpPlaceholder.parentNode){ 1443 modal.__ffpPlaceholder.parentNode.insertBefore(modal, modal.__ffpPlaceholder.nextSibling); 1444 } 1445 } 1446 function replyTextarea(){ return qs('#reply-box [data-ffp-editor] textarea'); } 1447 function focusReply(post){ 1448 var box=qs('#reply-box'); 1449 var ta=replyTextarea(); 1450 if(!box || !ta) return; 1451 var author=post ? (post.getAttribute('data-quote-author') || '') : ''; 1452 if(box.scrollIntoView) box.scrollIntoView({behavior:'smooth', block:'start'}); 1453 setTimeout(function(){ 1454 ta.focus(); 1455 if(author && !ta.value.trim()){ 1456 ta.value='@'+author+' '; 1457 ta.setSelectionRange(ta.value.length, ta.value.length); 1458 ta.dispatchEvent(new Event('input',{bubbles:true})); 1459 } 1460 var status=qs('[data-quote-status]'); 1461 if(status) status.textContent=author ? (author + ' kullanıcısına hızlı cevap yazıyorsunuz.') : 'Hızlı cevap alanı hazır.'; 1462 },180); 1463 } 1464 document.addEventListener('click', function(e){ 1465 var rate=e.target.closest('[data-first-post-rate-open]'); 1466 if(rate){ e.preventDefault(); var m=openEdit(rate.getAttribute('data-post-edit-open')); if(m) prepareFirstPostRating(m); return; } 1467 var open=e.target.closest('[data-post-edit-open]'); 1468 if(open){ e.preventDefault(); openEdit(open.getAttribute('data-post-edit-open')); return; } 1469 var close=e.target.closest('[data-post-edit-close]'); 1470 if(close){ e.preventDefault(); closeEdit(close.closest('[data-post-edit-modal]')); return; } 1471 var quick=e.target.closest('[data-quick-reply-post]'); 1472 if(quick){ e.preventDefault(); focusReply(quick.closest('[data-quote-post]')); return; } 1473 }); 1474 document.addEventListener('keydown', function(e){ 1475 if(e.key==='Escape') qsa('[data-post-edit-modal]:not([hidden])').forEach(closeEdit); 1476 }); 1477})(); 1478 1479/* geliÅmiÅ forum alıntı sistemi - tam alıntı, seçili metin, hızlı cevap ve çoklu alıntı */ 1480(function(){ 1481 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 1482 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 1483 function text(value){ return String(value == null ? '' : value); } 1484 function esc(value){ return text(value).replace(/[&<>"']/g, function(ch){ return ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]); }); } 1485 function cleanQuoteText(value){ 1486 return text(value) 1487 .replace(/\u00a0/g, ' ') 1488 .replace(/[ \t]+\n/g, '\n') 1489 .replace(/\n[ \t]+/g, '\n') 1490 .replace(/\n{4,}/g, '\n\n\n') 1491 .trim(); 1492 } 1493 function cleanAuthor(value){ 1494 value = text(value).replace(/[\[\]\r\n=]/g, ' ').replace(/\s+/g, ' ').trim(); 1495 return value.substring(0, 80) || 'Kullanıcı'; 1496 } 1497 function quoteCode(author, body){ 1498 body = cleanQuoteText(body); 1499 if(!body) return ''; 1500 return '[quote=' + cleanAuthor(author) + ']\n' + body + '\n[/quote]\n'; 1501 } 1502 function replyTextarea(){ return qs('#reply-box [data-ffp-editor] textarea'); } 1503 function replyBox(){ return qs('#reply-box'); } 1504 function setStatus(message){ 1505 var node = qs('[data-quote-status]'); 1506 if(node) node.textContent = message || 'Konuya hızlı cevap ekle'; 1507 } 1508 function scrollReply(){ 1509 var box = replyBox(); 1510 if(box && box.scrollIntoView) box.scrollIntoView({behavior:'smooth', block:'start'}); 1511 var ta = replyTextarea(); 1512 if(ta) setTimeout(function(){ ta.focus(); }, 180); 1513 } 1514 function insertAtCursor(value){ 1515 var ta = replyTextarea(); 1516 if(!ta || !value) return false;
1517 ta.focus(); 1518 var start = ta.selectionStart || 0, end = ta.selectionEnd || 0, current = ta.value || ''; 1519 var before = current.substring(0, start); 1520 var after = current.substring(end); 1521 var prefix = before && !/\n\n$/.test(before) ? (before.slice(-1) === '\n' ? '\n' : '\n\n') : ''; 1522 var suffix = after && !/^\n/.test(after) ? '\n' : ''; 1523 var insert = prefix + value + suffix; 1524 ta.value = before + insert + after; 1525 var pos = before.length + insert.length; 1526 ta.setSelectionRange(pos, pos); 1527 ta.dispatchEvent(new Event('input', {bubbles:true})); 1528 scrollReply(); 1529 return true; 1530 } 1531 function postFromNode(node){ 1532 if(!node) return null; 1533 if(node.nodeType === 3) node = node.parentElement; 1534 return node && node.closest ? node.closest('[data-quote-post]') : null; 1535 } 1536 function postBody(post){ return post ? qs('.post-body', post) : null; } 1537 function fullPostText(post){ 1538 var body = postBody(post); 1539 return cleanQuoteText(body ? (body.innerText || body.textContent || '') : (post ? post.getAttribute('data-quote-body') : '')); 1540 } 1541 function postPayload(post, selectedText){ 1542 if(!post) return null; 1543 var body = selectedText ? cleanQuoteText(selectedText) : fullPostText(post); 1544 if(!body) return null; 1545 return { 1546 key: (selectedText ? 'sel:' : 'post:') + (post.getAttribute('data-quote-post-id') || '') + ':' + body.substring(0, 80), 1547 postId: post.getAttribute('data-quote-post-id') || '', 1548 author: post.getAttribute('data-quote-author') || 'Kullanıcı', 1549 body: body, 1550 partial: !!selectedText 1551 }; 1552 } 1553 1554 var stack = []; 1555 function panel(){ return qs('[data-quote-compose-panel]'); }
1556 function renderStack(){ 1557 var p = panel(); 1558 var list = qs('[data-quote-stack-list]'); 1559 var count = qs('[data-quote-stack-count]'); 1560 if(p) p.hidden = stack.length === 0; 1561 if(count) count.textContent = stack.length + ' alıntı seçildi'; 1562 if(list){ 1563 if(!stack.length){ list.innerHTML = ''; } 1564 else { 1565 list.innerHTML = stack.map(function(item, index){ 1566 var shortBody = item.body.length > 170 ? item.body.substring(0,170) + 'â¦' : item.body; 1567 return '<article class="quote-stack-item" data-quote-stack-index="'+index+'">'+ 1568 '<div><strong>'+esc(item.author)+'</strong><small>'+(item.partial ? 'Seçili metin' : 'Tam yazı')+(item.postId ? ' · #'+esc(item.postId) : '')+'</small><p>'+esc(shortBody)+'</p></div>'+ 1569 '<button type="button" class="quote-stack-remove" data-quote-remove-index="'+index+'" aria-label="Alıntıyı kaldır">â</button>'+ 1570 '</article>'; 1571 }).join(''); 1572 } 1573 } 1574 qsa('[data-quote-multi]').forEach(function(btn){ 1575 var post = btn.closest('[data-quote-post]'); 1576 var id = post ? (post.getAttribute('data-quote-post-id') || '') : ''; 1577 var active = !!id && stack.some(function(item){ return item.key.indexOf('post:'+id+':') === 0; }); 1578 btn.classList.toggle('is-active', active); 1579 btn.setAttribute('aria-pressed', active ? 'true' : 'false'); 1580 if(active) btn.innerHTML = '<span aria-hidden="true">â</span> Ãokluya Eklendi'; 1581 else btn.innerHTML = '<span aria-hidden="true">ï¼</span> Ãoklu Alıntı'; 1582 }); 1583 } 1584 function addStack(item){ 1585 if(!item) return; 1586 var exists = stack.some(function(old){ return old.key === item.key; }); 1587 if(!exists) stack.push(item); 1588 renderStack(); 1589 setStatus('Alıntı çoklu listeye eklendi. Dilersen baÅka yazıları da seçebilirsin.'); 1590 var p = panel(); if(p && p.scrollIntoView) p.scrollIntoView({behavior:'smooth', block:'nearest'}); 1591 } 1592 function toggleFullStack(post){ 1593 var item = postPayload(post, ''); 1594 if(!item) return; 1595 var before = stack.length; 1596 stack = stack.filter(function(old){ return old.key !== item.key; }); 1597 if(stack.length === before) addStack(item); else { renderStack(); setStatus('Alıntı çoklu listeden kaldırıldı.'); } 1598 } 1599 function clearStack(){ stack = []; renderStack(); setStatus('Ãoklu alıntılar temizlendi.'); } 1600 function insertStack(){ 1601 if(!stack.length){ setStatus('Ãnce çoklu alıntıya yazı ekleyin.'); return; } 1602 var code = stack.map(function(item){ return quoteCode(item.author, item.body); }).join('\n'); 1603 if(insertAtCursor(code)){ clearStack(); setStatus('Ãoklu alıntılar cevap alanına eklendi.'); } 1604 } 1605 function insertQuote(item){ 1606 if(!item) return; 1607 var code = quoteCode(item.author, item.body); 1608 if(insertAtCursor(code)) setStatus((item.partial ? 'Seçili metin' : 'Yazı') + ' cevap alanına alıntı olarak eklendi.'); 1609 } 1610 1611 var quick = null; 1612 var savedSelection = null; 1613 var selectionTimer = null; 1614 function ensureQuick(){ 1615 if(quick) return quick; 1616 quick = document.createElement('div'); 1617 quick.className = 'quote-select-popover'; 1618 quick.hidden = true; 1619 quick.innerHTML = '<button type="button" data-quote-selection-reply>â Seçili metni alıntıla</button><button type="button" data-quote-selection-multi>ï¼ Ãokluya ekle</button>'; 1620 document.body.appendChild(quick); 1621 1622 // Mobil tarayıcılarda popover butonuna dokununca seçim anlık kapanır. 1623 // Bu olayları durdurarak önce savedSelection korunur, sonra click güvenle çalıÅır. 1624 ['mousedown','pointerdown','touchstart'].forEach(function(evtName){ 1625 quick.addEventListener(evtName, function(ev){ 1626 ev.preventDefault(); 1627 ev.stopPropagation(); 1628 }, {passive:false}); 1629 }); 1630 return quick; 1631 } 1632 function hideQuick(){ 1633 if(quick) quick.hidden = true; 1634 } 1635 function nodeElement(node){ 1636 if(!node) return null; 1637 return node.nodeType === 3 ? node.parentElement : node; 1638 } 1639 function nodeInside(parent, node){ 1640 var el = nodeElement(node); 1641 return !!(parent && el && parent.contains(el)); 1642 } 1643 function selectionOwnerPost(range, sel){ 1644 return postFromNode(range.commonAncestorContainer) || postFromNode(range.startContainer) || postFromNode(range.endContainer) || postFromNode(sel.anchorNode) || postFromNode(sel.focusNode); 1645 } 1646 function scheduleSelectionCapture(delay){ 1647 if(selectionTimer) clearTimeout(selectionTimer);
1648 selectionTimer = setTimeout(captureSelection, typeof delay === 'number' ? delay : 60); 1649 } 1650 function captureSelection(){ 1651 selectionTimer = null; 1652 var active = document.activeElement; 1653 if(active && active.closest && active.closest('textarea,input,select,[contenteditable="true"],[data-ffp-editor]')) return; 1654 var sel = window.getSelection ? window.getSelection() : null; 1655 if(!sel || sel.rangeCount === 0 || sel.isCollapsed){ 1656 hideQuick(); 1657 return; 1658 } 1659 var selectedText = cleanQuoteText(sel.toString()); 1660 if(selectedText.length < 2){ 1661 hideQuick(); 1662 return; 1663 } 1664 var range; 1665 try { range = sel.getRangeAt(0); } catch(err) { hideQuick(); return; } 1666 var post = selectionOwnerPost(range, sel); 1667 var body = postBody(post); 1668 if(!post || !body || !nodeInside(body, range.startContainer) || !nodeInside(body, range.endContainer)){ 1669 hideQuick(); 1670 return; 1671 } 1672 savedSelection = postPayload(post, selectedText); 1673 if(!savedSelection){ 1674 hideQuick(); 1675 return; 1676 } 1677 var rect = range.getBoundingClientRect ? range.getBoundingClientRect() : null; 1678 if((!rect || (!rect.width && !rect.height)) && range.getClientRects){ 1679 var rects = range.getClientRects(); 1680 if(rects && rects.length) rect = rects[0]; 1681 } 1682 if(!rect){ 1683 hideQuick(); 1684 return; 1685 } 1686 var q = ensureQuick(); 1687 q.hidden = false; 1688 q.setAttribute('aria-hidden','false'); 1689 1690 var popWidth = Math.min(300, Math.max(240, q.offsetWidth || 260)); 1691 var viewportW = window.innerWidth || document.documentElement.clientWidth || 360; 1692 var viewportH = window.innerHeight || document.documentElement.clientHeight || 640; 1693 var left = Math.max(10, Math.min(viewportW - popWidth - 10, rect.left + (rect.width / 2) - (popWidth / 2))); 1694 var top = rect.top - (q.offsetHeight || 46) - 10; 1695 if(top < 10) top = Math.min(viewportH - (q.offsetHeight || 46) - 12, rect.bottom + 10); 1696 q.style.left = left + 'px'; 1697 q.style.top = Math.max(10, top) + 'px'; 1698 } 1699 1700 document.addEventListener('click', function(e){ 1701 var quote = e.target.closest('[data-quote-reply]'); 1702 if(quote){ e.preventDefault(); insertQuote(postPayload(quote.closest('[data-quote-post]'), '')); return; } 1703 var multi = e.target.closest('[data-quote-multi]'); 1704 if(multi){ e.preventDefault(); toggleFullStack(multi.closest('[data-quote-post]')); return; } 1705 var insertBtn = e.target.closest('[data-quote-insert-stack]'); 1706 if(insertBtn){ e.preventDefault(); insertStack(); return; } 1707 var clearBtn = e.target.closest('[data-quote-clear-stack]'); 1708 if(clearBtn){ e.preventDefault(); clearStack(); return; } 1709 var remove = e.target.closest('[data-quote-remove-index]'); 1710 if(remove){ e.preventDefault(); var idx = parseInt(remove.getAttribute('data-quote-remove-index'),10); if(!isNaN(idx)){ stack.splice(idx,1); renderStack(); } return; } 1711 var selectionReply = e.target.closest('[data-quote-selection-reply]'); 1712 if(selectionReply){ e.preventDefault(); insertQuote(savedSelection); hideQuick(); return; } 1713 var selectionMulti = e.target.closest('[data-quote-selection-multi]'); 1714 if(selectionMulti){ e.preventDefault(); addStack(savedSelection); hideQuick(); return; } 1715 if(quick && !e.target.closest('.quote-select-popover')) hideQuick(); 1716 }); 1717 document.addEventListener('mouseup', function(){ scheduleSelectionCapture(30); }); 1718 document.addEventListener('pointerup', function(){ scheduleSelectionCapture(50); }); 1719 document.addEventListener('touchend', function(){ scheduleSelectionCapture(140); }, {passive:true}); 1720 document.addEventListener('keyup', function(e){ if(e.key === 'Shift' || e.key.indexOf('Arrow') === 0) scheduleSelectionCapture(30); }); 1721 document.addEventListener('selectionchange', function(){ scheduleSelectionCapture(120); }); 1722 window.addEventListener('scroll', function(){ if(quick && !quick.hidden) scheduleSelectionCapture(80); }, {passive:true}); 1723 document.addEventListener('DOMContentLoaded', renderStack); 1724})(); 1725 1726 1727/* ticaret puanı modalı */ 1728(function(){ 1729 function qs(sel, ctx){ return (ctx||document).querySelector(sel); } 1730 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx||document).querySelectorAll(sel)); } 1731 function body(){ return document.body || document.documentElement; } 1732 function openTrade(id){ 1733 var modal=document.getElementById(id); if(!modal) return; 1734 if(!modal.__ffpTradePlaceholder){ 1735 modal.__ffpTradePlaceholder=document.createComment('trade-score-modal-placeholder:'+id); 1736 if(modal.parentNode) modal.parentNode.insertBefore(modal.__ffpTradePlaceholder, modal); 1737 } 1738 if(modal.parentNode !== body()) body().appendChild(modal); 1739 modal.hidden=false; modal.setAttribute('aria-hidden','false'); body().classList.add('trade-score-opened'); 1740 setTimeout(function(){ var first=qs('input[name="title"], textarea, button', modal); if(first) first.focus(); },50); 1741 } 1742 function closeTrade(modal){ 1743 if(!modal) modal=qs('[data-trade-modal]:not([hidden])'); 1744 if(!modal) return; 1745 modal.hidden=true; modal.setAttribute('aria-hidden','true'); 1746 if(modal.__ffpTradePlaceholder && modal.__ffpTradePlaceholder.parentNode){ modal.__ffpTradePlaceholder.parentNode.insertBefore(modal, modal.__ffpTradePlaceholder); } 1747 if(!qs('[data-trade-modal]:not([hidden])')) body().classList.remove('trade-score-opened'); 1748 } 1749 document.addEventListener('click', function(e){ 1750 var open=e.target.closest('[data-trade-open]'); 1751 if(open){ e.preventDefault(); openTrade(open.getAttribute('data-trade-open')||''); return; } 1752 var close=e.target.closest('[data-trade-close]'); 1753 if(close){ e.preventDefault(); closeTrade(close.closest('[data-trade-modal]')); return; } 1754 }); 1755 document.addEventListener('keydown', function(e){ if(e.key==='Escape') closeTrade(); }); 1756})(); 1757 1758/* ticaret puanı seçim kartları için eski mobil tarayıcı uyumluluÄu */ 1759(function(){ 1760 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx||document).querySelectorAll(sel)); } 1761 function syncTradeCards(scope){ 1762 qsa('.trade-type-grid, .compact-trade-types', scope).forEach(function(group){
1763 qsa('.trade-type-card', group).forEach(function(card){ 1764 var input = card.querySelector('input[type="radio"]'); 1765 card.classList.toggle('is-selected', !!(input && input.checked)); 1766 }); 1767 }); 1768 } 1769 document.addEventListener('change', function(e){ 1770 if(e.target && e.target.matches('.trade-type-card input[type="radio"]')){ 1771 var group = e.target.closest('.trade-type-grid, .compact-trade-types') || document; 1772 syncTradeCards(group); 1773 } 1774 }); 1775 document.addEventListener('click', function(e){ 1776 var card = e.target.closest('.trade-type-card'); 1777 if(card){ 1778 var input = card.querySelector('input[type="radio"]'); 1779 if(input){ 1780 input.checked = true; 1781 var ev; 1782 if(typeof Event === 'function'){ ev = new Event('change', {bubbles:true}); } 1783 else { ev = document.createEvent('Event'); ev.initEvent('change', true, true); } 1784 input.dispatchEvent(ev); 1785 } 1786 } 1787 }); 1788 document.addEventListener('DOMContentLoaded', function(){ syncTradeCards(document); }); 1789})(); 1790 1791/* mobil forum yazısı kullanıcı kartı aç/kapat */ 1792(function(){ 1793 function closest(el, sel){ return el && (el.closest ? el.closest(sel) : null); } 1794 function setState(card, open){ 1795 if(!card) return; 1796 card.classList.toggle('is-user-open', !!open); 1797 var btn = card.querySelector('[data-post-user-toggle]'); 1798 if(btn) btn.setAttribute('aria-expanded', open ? 'true' : 'false'); 1799 } 1800 document.addEventListener('click', function(e){ 1801 var btn = closest(e.target, '[data-post-user-toggle]'); 1802 if(!btn) return; 1803 e.preventDefault(); 1804 var card = closest(btn, '.post-user'); 1805 setState(card, !(card && card.classList.contains('is-user-open'))); 1806 }); 1807 document.addEventListener('keydown', function(e){ 1808 if(e.key !== 'Escape') return; 1809 Array.prototype.slice.call(document.querySelectorAll('.post-user.is-user-open')).forEach(function(card){ setState(card, false); }); 1810 }); 1811})(); 1812 1813/* ilk yazı BeÄen / BeÄenme saÄlam AJAX sistemi */ 1814(function(){ 1815 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 1816 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 1817 function closest(el, sel){ 1818 while(el && el.nodeType === 1){ 1819 if(el.matches && el.matches(sel)) return el; 1820 el = el.parentElement; 1821 } 1822 return null; 1823 } 1824 function setStatus(card, msg, cls){ 1825 var status = qs('[data-first-post-reaction-status]', card); 1826 if(!status) return; 1827 status.textContent = msg || ''; 1828 status.classList.remove('is-ok','is-error','is-muted'); 1829 if(cls) status.classList.add(cls); 1830 } 1831 function countsVisible(card, payload){ 1832 var like = parseInt(payload && payload.like_count || 0, 10) || 0; 1833 var dislike = parseInt(payload && payload.dislike_count || 0, 10) || 0; 1834 var reaction = String(payload && payload.user_reaction || ''); 1835 return !!reaction || like > 0 || dislike > 0; 1836 } 1837 function updateCard(card, payload){ 1838 if(!card || !payload) return; 1839 var like = parseInt(payload.like_count || 0, 10); 1840 var dislike = parseInt(payload.dislike_count || 0, 10); 1841 var reaction = String(payload.user_reaction || ''); 1842 var likeCount = qs('[data-reaction-count="like"]', card); 1843 var dislikeCount = qs('[data-reaction-count="dislike"]', card); 1844 if(likeCount) likeCount.textContent = String(isNaN(like) ? 0 : like); 1845 if(dislikeCount) dislikeCount.textContent = String(isNaN(dislike) ? 0 : dislike); 1846 card.classList.toggle('has-visible-counts', countsVisible(card, payload)); 1847 qsa('[data-first-post-reaction]', card).forEach(function(btn){ 1848 btn.classList.toggle('is-active', btn.getAttribute('data-first-post-reaction') === reaction); 1849 btn.setAttribute('aria-pressed', btn.classList.contains('is-active') ? 'true' : 'false'); 1850 btn.disabled = false; 1851 }); 1852 card.setAttribute('data-liked', reaction); 1853 } 1854 function ajaxPost(url, fd, done, fail){ 1855 if(window.fetch && window.FormData){ 1856 var timedOut = false; 1857 var timer = window.setTimeout(function(){ timedOut = true; fail({message:'İstek zaman aÅımına uÄradı.'}); }, 15000); 1858 fetch(url, { 1859 method: 'POST', 1860 body: fd, 1861 credentials: 'same-origin', 1862 cache: 'no-store', 1863 headers: {'X-Requested-With':'XMLHttpRequest','Accept':'application/json'} 1864 }).then(function(r){ 1865 return r.json().catch(function(){ return {ok:false,message:'Sunucu JSON yanıtı vermedi. /update çalıÅtırıp tekrar deneyin.'}; }).then(function(data){ data.__status = r.status; return data; }); 1866 }).then(function(payload){ 1867 if(timedOut) return; 1868 window.clearTimeout(timer); 1869 done(payload || {}); 1870 }).catch(function(){ 1871 if(timedOut) return; 1872 window.clearTimeout(timer); 1873 fail({message:'BaÄlantı hatası. Lütfen tekrar deneyin.'}); 1874 }); 1875 return; 1876 } 1877 try { 1878 var xhr = new XMLHttpRequest(); 1879 xhr.open('POST', url, true); 1880 xhr.setRequestHeader('X-Requested-With','XMLHttpRequest'); 1881 xhr.setRequestHeader('Accept','application/json'); 1882 xhr.timeout = 15000; 1883 xhr.onreadystatechange = function(){ 1884 if(xhr.readyState !== 4) return; 1885 var payload = null; 1886 try { payload = JSON.parse(xhr.responseText || '{}'); } catch(e) { payload = {ok:false,message:'Sunucu yanıtı okunamadı.'}; } 1887 done(payload || {}); 1888 }; 1889 xhr.ontimeout = function(){ fail({message:'İstek zaman aÅımına uÄradı.'}); }; 1890 xhr.onerror = function(){ fail({message:'BaÄlantı hatası. Lütfen tekrar deneyin.'}); }; 1891 xhr.send(fd); 1892 } catch(e) { 1893 fail({message:'Tarayıcı bu iÅlemi desteklemiyor.'}); 1894 } 1895 } 1896 function submitReaction(form, reaction, btn){ 1897 if(!form) return false;
1898 var card = closest(form, '[data-first-post-reaction-card]'); 1899 if(!card) return false; 1900 var hidden = qs('input[name="reaction"]', form); 1901 if(hidden) hidden.value = reaction; 1902 if(btn && (btn.disabled || btn.classList.contains('is-disabled'))) return true; 1903 if(card.classList.contains('is-loading')) return true; 1904 1905 var fd = new FormData(form); 1906 fd.set('reaction', reaction || 'like'); 1907 fd.set('ajax', '1'); 1908 var tokenInput = qs('input[name="_csrf"]', form); 1909 var token = tokenInput ? tokenInput.value : ((document.body && document.body.getAttribute('data-csrf-token')) || ''); 1910 if(token) fd.set('_csrf', token); 1911 1912 card.classList.add('is-loading'); 1913 qsa('[data-first-post-reaction]', card).forEach(function(b){ b.disabled = true; }); 1914 setStatus(card, 'İÅleniyor...', 'is-muted'); 1915 ajaxPost(form.getAttribute('action') || form.action, fd, function(payload){ 1916 card.classList.remove('is-loading'); 1917 qsa('[data-first-post-reaction]', card).forEach(function(b){ b.disabled = false; }); 1918 if(payload && (payload.like_count !== undefined || payload.dislike_count !== undefined || payload.user_reaction !== undefined)) updateCard(card, payload); 1919 if(payload && payload.ok){ setStatus(card, payload.message || 'Oy kaydedildi.', 'is-ok'); } 1920 else { setStatus(card, (payload && payload.message) ? payload.message : 'Oy kaydedilemedi. Lütfen tekrar deneyin.', 'is-error'); } 1921 }, function(payload){ 1922 card.classList.remove('is-loading'); 1923 qsa('[data-first-post-reaction]', card).forEach(function(b){ b.disabled = false; }); 1924 setStatus(card, (payload && payload.message) ? payload.message : 'BaÄlantı hatası. Lütfen tekrar deneyin.', 'is-error'); 1925 }); 1926 return true; 1927 } 1928 document.addEventListener('click', function(e){ 1929 var btn = closest(e.target, '[data-first-post-reaction]'); 1930 if(!btn) return; 1931 var form = closest(btn, '[data-first-post-reaction-form]'); 1932 if(!form) return; 1933 e.preventDefault(); 1934 e.stopPropagation(); 1935 submitReaction(form, btn.getAttribute('data-first-post-reaction') || btn.value || 'like', btn); 1936 }, true); 1937 document.addEventListener('submit', function(e){ 1938 var form = closest(e.target, '[data-first-post-reaction-form]'); 1939 if(!form) return; 1940 e.preventDefault(); 1941 var submitter = e.submitter || qs('[data-first-post-reaction].is-pending', form) || qs('[data-first-post-reaction]', form); 1942 submitReaction(form, (submitter && (submitter.getAttribute('data-first-post-reaction') || submitter.value)) || (qs('input[name="reaction"]', form) || {}).value || 'like', submitter); 1943 }, true); 1944})(); 1945 1946/* ilk yazı aksiyon kartı dıÅarı alındı + ayrı deÄerlendirme penceresi */ 1947(function(){ 1948 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 1949 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 1950 function body(){ return document.body || document.documentElement; } 1951 function ratingRegex(){ return /\s*\[rating(?:=([1-5]))?\]\s*([\s\S]*?)\s*\[\/rating\]\s*/i; } 1952 function clean(value){ return String(value == null ? '' : value).replace(/\r\n/g,'\n').trim(); } 1953 function setScore(modal, score){ 1954 score = Math.max(1, Math.min(5, parseInt(score || 5, 10) || 5)); 1955 var hidden = qs('[data-first-rating-score-value]', modal); 1956 if(hidden) hidden.value = String(score); 1957 qsa('[data-first-rating-score]', modal).forEach(function(btn){ 1958 var on = parseInt(btn.getAttribute('data-first-rating-score') || '0', 10) === score; 1959 btn.classList.toggle('is-active', on); 1960 btn.setAttribute('aria-pressed', on ? 'true' : 'false'); 1961 }); 1962 } 1963 function parseCurrent(modal){ 1964 var bodyField = qs('[data-first-rating-body]', modal); 1965 var raw = bodyField ? String(bodyField.value || '') : ''; 1966 var m = raw.match(ratingRegex()); 1967 var title = qs('[data-first-rating-title]', modal); 1968 var text = qs('[data-first-rating-text]', modal); 1969 if(m){ 1970 setScore(modal, m[1] || 5); 1971 var lines = clean(m[2] || '').split('\n'); 1972 if(title) title.value = clean(lines.shift() || 'Genel deÄerlendirme'); 1973 if(text) text.value = clean(lines.join('\n')); 1974 } else { 1975 setScore(modal, 5); 1976 if(title) title.value = ''; 1977 if(text) text.value = ''; 1978 } 1979 } 1980 function openModal(id){ 1981 var modal = document.getElementById(id); 1982 if(!modal) return; 1983 if(!modal.__ffpPlaceholder){ 1984 modal.__ffpPlaceholder = document.createComment('first-rating-modal-placeholder:'+id); 1985 if(modal.parentNode) modal.parentNode.insertBefore(modal.__ffpPlaceholder, modal); 1986 } 1987 if(modal.parentNode !== body()) body().appendChild(modal); 1988 parseCurrent(modal); 1989 modal.hidden = false;
1990 modal.setAttribute('aria-hidden','false'); 1991 body().classList.add('first-rating-opened'); 1992 setTimeout(function(){ var first = qs('[data-first-rating-title]', modal) || qs('button,input,textarea', modal); if(first) first.focus(); }, 50); 1993 } 1994 function closeModal(modal){ 1995 if(!modal) return; 1996 modal.hidden = true; 1997 modal.setAttribute('aria-hidden','true'); 1998 body().classList.remove('first-rating-opened'); 1999 if(modal.__ffpPlaceholder && modal.__ffpPlaceholder.parentNode){ 2000 modal.__ffpPlaceholder.parentNode.insertBefore(modal, modal.__ffpPlaceholder.nextSibling); 2001 } 2002 } 2003 function buildRatingBody(form){ 2004 var bodyField = qs('[data-first-rating-body]', form); 2005 if(!bodyField) return; 2006 var score = (qs('[data-first-rating-score-value]', form) || {}).value || '5'; 2007 var title = clean((qs('[data-first-rating-title]', form) || {}).value || 'Genel deÄerlendirme'); 2008 var text = clean((qs('[data-first-rating-text]', form) || {}).value || 'DeÄerlendirme metni'); 2009 var base = String(bodyField.value || '').replace(ratingRegex(), '\n').replace(/\s+$/,''); 2010 bodyField.value = base + '\n\n[rating=' + score + ']\n' + title + '\n' + text + '\n[/rating]'; 2011 } 2012 document.addEventListener('click', function(e){ 2013 var open = e.target.closest('[data-first-rating-open]'); 2014 if(open){ e.preventDefault(); openModal(open.getAttribute('data-first-rating-open')); return; } 2015 var close = e.target.closest('[data-first-rating-close]'); 2016 if(close){ e.preventDefault(); closeModal(close.closest('[data-first-rating-modal]')); return; } 2017 var star = e.target.closest('[data-first-rating-score]'); 2018 if(star){ e.preventDefault(); setScore(star.closest('[data-first-rating-modal]'), star.getAttribute('data-first-rating-score')); return; } 2019 }); 2020 document.addEventListener('submit', function(e){ 2021 var form = e.target.closest('[data-first-rating-form]'); 2022 if(!form) return; 2023 buildRatingBody(form); 2024 }); 2025 document.addEventListener('keydown', function(e){ 2026 if(e.key !== 'Escape') return; 2027 qsa('[data-first-rating-modal]:not([hidden])').forEach(closeModal); 2028 }); 2029})(); 2030 2031/* geliÅmiÅ forum benzeri konu içi yönetim menüleri */ 2032(function(){ 2033 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 2034 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 2035 function closest(el, sel){ return el && el.closest ? el.closest(sel) : null; } 2036 function checks(){ return qsa('[data-vb-post-checkbox]'); } 2037 function postOf(cb){ return closest(cb, '[data-vb-post]'); } 2038 function selected(){ return checks().filter(function(cb){ return cb.checked; }); } 2039 function toast(msg, error){ 2040 var old = qs('.vb-toast'); if(old) old.remove(); 2041 var el = document.createElement('div'); el.className = 'vb-toast' + (error ? ' is-error' : ''); el.textContent = msg; 2042 document.body.appendChild(el); 2043 setTimeout(function(){ if(el && el.parentNode) el.parentNode.removeChild(el); }, 2600); 2044 } 2045 function update(){ 2046 var all = checks(); var sel = selected(); 2047 qsa('[data-vb-selected-count]').forEach(function(el){ el.textContent = sel.length + ' mesaj seçili'; }); 2048 qsa('[data-vb-master-checkbox]').forEach(function(master){ 2049 master.checked = all.length > 0 && sel.length === all.length; 2050 master.indeterminate = sel.length > 0 && sel.length < all.length; 2051 }); 2052 all.forEach(function(cb){ var p = postOf(cb); if(p) p.classList.toggle('vb-view-selected', cb.checked); }); 2053 } 2054 function setAll(mode){ 2055 checks().forEach(function(cb){ 2056 if(mode === 'all') cb.checked = true; 2057 else if(mode === 'none') cb.checked = false; 2058 else if(mode === 'invert') cb.checked = !cb.checked; 2059 else if(mode === 'deleted') cb.checked = (postOf(cb) || {}).getAttribute('data-vb-deleted') === '1'; 2060 else if(mode === 'rich') cb.checked = (postOf(cb) || {}).getAttribute('data-vb-rich') === '1'; 2061 else if(mode === 'hidden') cb.checked = (postOf(cb) || {}).getAttribute('data-vb-deleted') === '1'; 2062 }); 2063 update(); 2064 } 2065 function clearViewFilter(){ qsa('[data-vb-post]').forEach(function(p){ p.classList.remove('vb-view-muted'); }); } 2066 function showOnlySelected(){ 2067 var sel = selected(); 2068 if(!sel.length){ toast('Ãnce görüntülenecek mesajları seçin.', true); return; } 2069 qsa('[data-vb-post]').forEach(function(p){ 2070 var cb = qs('[data-vb-post-checkbox]', p); 2071 p.classList.toggle('vb-view-muted', !(cb && cb.checked)); 2072 }); 2073 toast('Sadece seçilen mesajlar gösteriliyor. Tümünü görmek için Hiçbirini Seçme kullanın.'); 2074 } 2075 function selectedText(){ 2076 return selected().map(function(cb){ 2077 var p = postOf(cb); if(!p) return ''; 2078 var id = cb.value || p.id || ''; 2079 var text = p.getAttribute('data-vb-post-text') || ''; 2080 return '#' + id + ' - ' + text; 2081 }
2081).filter(Boolean).join('\n\n'); 2082 } 2083 function copySelected(){ 2084 var text = selectedText(); 2085 if(!text){ toast('Ãnce kopyalanacak mesajları seçin.', true); return; } 2086 if(navigator.clipboard && navigator.clipboard.writeText){ 2087 navigator.clipboard.writeText(text).then(function(){ toast('Seçilen mesajlar panoya kopyalandı.'); }, function(){ fallbackCopy(text); }); 2088 } else fallbackCopy(text); 2089 } 2090 function fallbackCopy(text){ 2091 var ta = document.createElement('textarea'); ta.value = text; ta.style.position = 'fixed'; ta.style.left = '-9999px'; 2092 document.body.appendChild(ta); ta.focus(); ta.select(); 2093 try { document.execCommand('copy'); toast('Seçilen mesajlar panoya kopyalandı.'); } catch(e){ toast('Tarayıcı panoya kopyalamayı engelledi.', true); } 2094 ta.remove(); 2095 } 2096 function openModal(id){ 2097 var modal = document.getElementById(id); if(!modal) return; 2098 if(!modal.__vbPlaceholder){ modal.__vbPlaceholder = document.createComment('vb-modal:'+id); if(modal.parentNode) modal.parentNode.insertBefore(modal.__vbPlaceholder, modal); } 2099 if(modal.parentNode !== document.body) document.body.appendChild(modal); 2100 modal.hidden = false; modal.setAttribute('aria-hidden','false'); document.body.classList.add('vb-modal-open'); 2101 setTimeout(function(){ var first = qs('input,select,textarea,button', modal); if(first) first.focus(); }, 40); 2102 } 2103 function closeModal(modal){ 2104 if(!modal) return; 2105 modal.hidden = true; modal.setAttribute('aria-hidden','true'); document.body.classList.remove('vb-modal-open'); 2106 if(modal.__vbPlaceholder && modal.__vbPlaceholder.parentNode){ modal.__vbPlaceholder.parentNode.insertBefore(modal, modal.__vbPlaceholder.nextSibling); } 2107 } 2108 document.addEventListener('change', function(e){ 2109 if(closest(e.target, '[data-vb-post-checkbox]')){ update(); return; } 2110 if(closest(e.target, '[data-vb-master-checkbox]')){ checks().forEach(function(cb){ cb.checked = e.target.checked; }); update(); } 2111 }); 2112 document.addEventListener('click', function(e){ 2113 var t = e.target; 2114 if(closest(t, '[data-vb-select-all]')){ e.preventDefault(); clearViewFilter(); setAll('all'); return; } 2115 if(closest(t, '[data-vb-select-none]')){ e.preventDefault(); setAll('none'); clearViewFilter(); return; } 2116 if(closest(t, '[data-vb-select-invert]')){ e.preventDefault(); clearViewFilter(); setAll('invert'); return; } 2117 if(closest(t, '[data-vb-select-deleted]')){ e.preventDefault(); clearViewFilter(); setAll('deleted'); return; } 2118 if(closest(t, '[data-vb-select-hidden]')){ e.preventDefault(); clearViewFilter(); setAll('hidden'); return; } 2119 if(closest(t, '[data-vb-select-rich]')){ e.preventDefault(); clearViewFilter(); setAll('rich'); return; } 2120 if(closest(t, '[data-vb-view-selected]')){ e.preventDefault(); showOnlySelected(); return; } 2121 if(closest(t, '[data-vb-copy-selected]')){ e.preventDefault(); copySelected(); return; } 2122 var openBtn = closest(t, '[data-vb-modal-open]'); 2123 if(openBtn){ 2124 e.preventDefault(); 2125 var parentMenu = closest(openBtn, '.vb-action-dd'); 2126 if(parentMenu) parentMenu.open = false; 2127 document.body.classList.remove('vb-menu-open'); 2128 openModal(openBtn.getAttribute('data-vb-modal-open')); 2129 return; 2130 } 2131 var closeBtn = closest(t, '[data-vb-modal-close]'); 2132 if(closeBtn){ e.preventDefault(); closeModal(closest(closeBtn, '[data-vb-modal]')); return; } 2133 var focusPostMenu = closest(t, '[data-vb-focus-post-menu]'); 2134 if(focusPostMenu){ 2135 e.preventDefault(); 2136 var menu = qs('[data-vb-post-menu]'); 2137 if(menu){ menu.open = true; menu.scrollIntoView({block:'nearest', behavior:'smooth'}); } 2138 return; 2139 } 2140 }); 2141 document.addEventListener('submit', function(e){ 2142 var form = e.target; 2143 if(form && form.id === 'topic-bulk-form'){ 2144 var btn = e.submitter; 2145 var action = btn ? (btn.value || '') : ''; 2146 if(!selected().length){ e.preventDefault(); toast('Toplu iÅlem için önce mesaj seçin.', true); return; } 2147 if(action === 'soft_delete_posts' && !confirm('Seçilen mesajlar yumuÅak silinsin mi?')) e.preventDefault(); 2148 if(action === 'permanent_delete_posts' && !confirm('Seçilen mesajlar kalıcı silinsin mi?')) e.preventDefault(); 2149 if(action === 'merge_posts' && selected().length < 2){ e.preventDefault(); toast('BirleÅtirme için en az 2 mesaj seçin.', true); } 2150 } 2151 }); 2152 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') qsa('[data-vb-modal]:not([hidden])').forEach(closeModal); }); 2153 update(); 2154})(); 2155 2156/* mobil konu/mesaj yönetim menülerini tek açık panel ve kompakt seçim sayacı yap */ 2157(function(){ 2158 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 2159 function closest(el, sel){ return el && el.closest ? el.closest(sel) : null; } 2160 var menus = qsa('.vb-action-dd'); 2161 if(!menus.length) return; 2162 function refreshCount(){ 2163 var checked = qsa('[data-vb-post-checkbox]:checked').length; 2164 qsa('[data-vb-selected-count]').forEach(function(el){ 2165 el.textContent = checked + (window.innerWidth <= 620 ? ' seÃ
2165§ili' : ' mesaj seçili'); 2166 var wrap = closest(el, '.vb-select-summary'); 2167 if(wrap) wrap.classList.toggle('has-selection', checked > 0); 2168 }); 2169 } 2170 function anyOpen(){ return menus.some(function(m){ return m.open; }); } 2171 function syncBody(){ document.body.classList.toggle('vb-menu-open', anyOpen()); } 2172 function closeMenus(except){ 2173 menus.forEach(function(menu){ if(menu !== except) menu.open = false; }); 2174 syncBody(); 2175 } 2176 menus.forEach(function(menu){ 2177 menu.addEventListener('toggle', function(){ 2178 if(menu.open) closeMenus(menu); 2179 syncBody(); 2180 }); 2181 }); 2182 document.addEventListener('click', function(e){ 2183 if(!closest(e.target, '.vb-action-dd') && !closest(e.target, '.vb-action-menu-panel')) closeMenus(null); 2184 if(closest(e.target, '.vb-menu-item')) setTimeout(function(){ closeMenus(null); refreshCount(); }, 30); 2185 }); 2186 document.addEventListener('change', function(e){ if(closest(e.target, '[data-vb-post-checkbox]') || closest(e.target, '[data-vb-master-checkbox]')) setTimeout(refreshCount, 0); }); 2187 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeMenus(null); }); 2188 window.addEventListener('resize', refreshCount, {passive:true}); 2189 refreshCount(); 2190})(); 2191 2192/* mobil alt sayfa gölgesine dokununca menüyü kapat */ 2193(function(){ 2194 document.addEventListener('click', function(e){ 2195 var openDetail = e.target && e.target.matches && e.target.matches('.vb-action-dd[open]') ? e.target : null; 2196 if(openDetail){ openDetail.open = false; document.body.classList.remove('vb-menu-open'); } 2197 }, true); 2198})(); 2199 2200/* toplu seçim kısayollarından sonra sayaç metnini mobil uyumlu yenile */ 2201(function(){ 2202 function qsa(sel){ return Array.prototype.slice.call(document.querySelectorAll(sel)); } 2203 function closest(el, sel){ return el && el.closest ? el.closest(sel) : null; } 2204 function refresh(){ 2205 var checked = qsa('[data-vb-post-checkbox]:checked').length; 2206 qsa('[data-vb-selected-count]').forEach(function(el){ 2207 el.textContent = checked + (window.innerWidth <= 620 ? ' seçili' : ' mesaj seçili'); 2208 var wrap = closest(el, '.vb-select-summary'); 2209 if(wrap) wrap.classList.toggle('has-selection', checked > 0); 2210 }); 2211 } 2212 document.addEventListener('click', function(e){ 2213 if(closest(e.target, '[data-vb-select-all]') || closest(e.target, '[data-vb-select-none]') || closest(e.target, '[data-vb-select-invert]') || closest(e.target, '[data-vb-select-deleted]') || closest(e.target, '[data-vb-select-rich]') || closest(e.target, '[data-vb-select-hidden]')) setTimeout(refresh, 20); 2214 }); 2215})(); 2216 2217 2218/* mobil konu/mesaj yönetim panelini gerçek viewport yüksekliÄine göre tam aç */ 2219(function(){ 2220 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 2221 function closest(el, sel){ return el && el.closest ? el.closest(sel) : null; } 2222 var menus = qsa('.vb-action-dd'); 2223 if(!menus.length) return; 2224 function viewportHeight(){ 2225 var vv = window.visualViewport; 2226 var h = vv && vv.height ? vv.height : window.innerHeight; 2227 document.documentElement.style.setProperty('--vb-vh', Math.max(320, Math.floor(h)) + 'px'); 2228 } 2229 function openMenus(){ return menus.filter(function(m){ return m.open; }); } 2230 function sync(){ 2231 var any = openMenus().length > 0; 2232 document.body.classList.toggle('vb-menu-open', any); 2233 menus.forEach(function(menu){ 2234 var summary = menu.querySelector('summary'); 2235 if(summary) summary.setAttribute('aria-expanded', menu.open ? 'true' : 'false'); 2236 if(menu.open){ 2237 var panel = menu.querySelector('.vb-action-menu-panel'); 2238 if(panel){ panel.style.scrollBehavior = 'auto'; panel.scrollTop = 0; } 2239 } 2240 }); 2241 } 2242 function closeAll(){ menus.forEach(function(m){ m.open = false; }); sync(); } 2243 function closeOthers(active){ menus.forEach(function(m){ if(m !== active) m.open = false; }); } 2244 menus.forEach(function(menu){ 2245 menu.addEventListener('toggle', function(){ 2246 viewportHeight(); 2247 if(menu.open) closeOthers(menu); 2248 requestAnimationFrame(sync); 2249 }); 2250 }); 2251 document.addEventListener('click', function(e){ 2252 if(closest(e.target, '[data-vb-menu-close]')){ e.preventDefault(); closeAll(); return; } 2253 if(closest(e.target, '.vb-action-menu-panel')) return;
2254 if(!closest(e.target, '.vb-action-dd')) closeAll(); 2255 }); 2256 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeAll(); }); 2257 window.addEventListener('resize', viewportHeight, {passive:true}); 2258 window.addEventListener('orientationchange', function(){ setTimeout(viewportHeight, 80); }, {passive:true}); 2259 if(window.visualViewport){ window.visualViewport.addEventListener('resize', viewportHeight, {passive:true}); window.visualViewport.addEventListener('scroll', viewportHeight, {passive:true}); } 2260 viewportHeight(); 2261})(); 2262 2263/* mobil konu/mesaj menülerini üstte deÄil, body altında gerçek bottom-sheet olarak aç */ 2264(function(){ 2265 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 2266 function closest(el, sel){ return el && el.closest ? el.closest(sel) : null; } 2267 var menus = qsa('.vb-action-dd'); 2268 if(!menus.length) return; 2269 var mq = window.matchMedia ? window.matchMedia('(max-width: 900px)') : {matches:false, addEventListener:function(){}}; 2270 var backdrop = null; 2271 var activeMenu = null; 2272 2273 function setViewportHeight(){ 2274 var vv = window.visualViewport; 2275 var h = vv && vv.height ? vv.height : window.innerHeight; 2276 document.documentElement.style.setProperty('--vb-vh', Math.max(320, Math.floor(h || 0)) + 'px'); 2277 } 2278 2279 function ensureBackdrop(){ 2280 if(backdrop && backdrop.parentNode) return backdrop; 2281 backdrop = document.createElement('button'); 2282 backdrop.type = 'button'; 2283 backdrop.className = 'vb-mobile-sheet-backdrop'; 2284 backdrop.setAttribute('aria-label', 'Menüyü kapat'); 2285 backdrop.addEventListener('click', closeAll); 2286 document.body.appendChild(backdrop); 2287 return backdrop; 2288 } 2289 2290 function getPanel(menu){ return menu ? menu.querySelector('.vb-action-menu-panel') || menu.__vbPanel : null; } 2291 2292 function portal(menu){ 2293 if(!mq.matches || !menu || !menu.open) return; 2294 var panel = getPanel(menu); 2295 if(!panel) return; 2296 setViewportHeight(); 2297 activeMenu = menu; 2298 if(!panel.__vbPlaceholder){ 2299 panel.__vbPlaceholder = document.createComment('vb-mobile-menu-placeholder'); 2300 if(panel.parentNode) panel.parentNode.insertBefore(panel.__vbPlaceholder, panel); 2301 } 2302 menu.__vbPanel = panel; 2303 ensureBackdrop(); 2304 if(panel.parentNode !== document.body) document.body.appendChild(panel); 2305 panel.classList.add('vb-mobile-sheet-active'); 2306 panel.style.scrollBehavior = 'auto'; 2307 panel.scrollTop = 0; 2308 document.body.classList.add('vb-mobile-sheet-ported', 'vb-menu-open'); 2309 var summary = menu.querySelector('summary'); 2310 if(summary) summary.setAttribute('aria-expanded', 'true'); 2311 } 2312 2313 function restore(menu){ 2314 if(!menu) return; 2315 var panel = menu.__vbPanel; 2316 if(panel){ 2317 panel.classList.remove('vb-mobile-sheet-active'); 2318 if(panel.__vbPlaceholder && panel.__vbPlaceholder.parentNode){ 2319 panel.__vbPlaceholder.parentNode.insertBefore(panel, panel.__vbPlaceholder.nextSibling); 2320 } 2321 menu.__vbPanel = null; 2322 } 2323 var summary = menu.querySelector('summary'); 2324 if(summary) summary.setAttribute('aria-expanded', menu.open ? 'true' : 'false'); 2325 } 2326 2327 function closeAll(){ 2328 menus.forEach(function(menu){ 2329 if(menu.open) menu.open = false; 2330 restore(menu); 2331 }); 2332 if(backdrop && backdrop.parentNode) backdrop.parentNode.removeChild(backdrop); 2333 document.body.classList.remove('vb-mobile-sheet-ported', 'vb-menu-open'); 2334 activeMenu = null; 2335 } 2336 2337 function closeOthers(except){ 2338 menus.forEach(function(menu){ 2339 if(menu !== except){ 2340 if(menu.open) menu.open = false; 2341 restore(menu); 2342 } 2343 }); 2344 } 2345 2346 menus.forEach(function(menu){ 2347 menu.addEventListener('toggle', function(){ 2348 if(menu.open){ 2349 closeOthers(menu); 2350 requestAnimationFrame(function(){ portal(menu); }); 2351 }else{ 2352 restore(menu); 2353 if(activeMenu === menu) activeMenu = null; 2354 if(!menus.some(function(m){ return m.open; })){ 2355 if(backdrop && backdrop.parentNode) backdrop.parentNode.removeChild(backdrop); 2356 document.body.classList.remove('vb-mobile-sheet-ported', 'vb-menu-open'); 2357 } 2358 } 2359 }); 2360 }); 2361 2362 document.addEventListener('click', function(e){ 2363 if(!mq.matches) return; 2364 if(closest(e.target, '[data-vb-menu-close]')){ e.preventDefault(); closeAll(); return; } 2365 if(closest(e.target, '.vb-action-menu-panel.vb-mobile-sheet-active')) return; 2366 if(activeMenu && !closest(e.target, '.vb-action-dd')) closeAll(); 2367 }, true); 2368 2369 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeAll(); }); 2370 2371 function onResize(){
2372 setViewportHeight(); 2373 if(!mq.matches){ closeAll(); } 2374 else if(activeMenu && activeMenu.open){ portal(activeMenu); } 2375 } 2376 window.addEventListener('resize', onResize, {passive:true}); 2377 window.addEventListener('orientationchange', function(){ setTimeout(onResize, 100); }, {passive:true}); 2378 if(window.visualViewport){ 2379 window.visualViewport.addEventListener('resize', onResize, {passive:true}); 2380 window.visualViewport.addEventListener('scroll', setViewportHeight, {passive:true}); 2381 } 2382 if(mq.addEventListener) mq.addEventListener('change', onResize); 2383 else if(mq.addListener) mq.addListener(onResize); 2384 setViewportHeight(); 2385})(); 2386 2387/* mobilde profil bilgi paneli ile konu/mesaj yönetim paneli birbirinin üstüne binmesin */ 2388(function(){ 2389 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 2390 function closest(el, sel){ return el && el.closest ? el.closest(sel) : null; } 2391 function isMobile(){ return window.matchMedia ? window.matchMedia('(max-width: 900px)').matches : window.innerWidth <= 900; } 2392 function closeUserPanels(except){ 2393 qsa('.post-user.is-user-open').forEach(function(card){ 2394 if(card === except) return; 2395 card.classList.remove('is-user-open'); 2396 var btn = card.querySelector('[data-post-user-toggle]'); 2397 if(btn) btn.setAttribute('aria-expanded','false'); 2398 }); 2399 syncBodyUserState(); 2400 } 2401 function closeVbMenus(){ 2402 qsa('.vb-action-dd[open]').forEach(function(menu){ menu.open = false; }); 2403 qsa('body > .vb-action-menu-panel.vb-mobile-sheet-active').forEach(function(panel){ 2404 panel.classList.remove('vb-mobile-sheet-active'); 2405 }); 2406 qsa('.vb-mobile-sheet-backdrop').forEach(function(backdrop){ 2407 if(backdrop.parentNode) backdrop.parentNode.removeChild(backdrop); 2408 }); 2409 document.body.classList.remove('vb-mobile-sheet-ported','vb-menu-open'); 2410 } 2411 function syncBodyUserState(){ 2412 document.body.classList.toggle('post-user-panel-open', qsa('.post-user.is-user-open').length > 0); 2413 } 2414 2415 document.addEventListener('click', function(e){ 2416 var userToggle = closest(e.target, '[data-post-user-toggle]'); 2417 if(userToggle){ 2418 var currentCard = closest(userToggle, '.post-user'); 2419 if(isMobile()) closeVbMenus(); 2420 closeUserPanels(currentCard); 2421 window.setTimeout(syncBodyUserState, 0); 2422 return; 2423 } 2424 2425 var vbTrigger = closest(e.target, '.vb-icon-trigger, .vb-master-check, [data-vb-menu-close]'); 2426 if(vbTrigger && isMobile()){ 2427 closeUserPanels(null); 2428 window.setTimeout(syncBodyUserState, 0); 2429 } 2430 }, true); 2431 2432 document.addEventListener('toggle', function(e){ 2433 var menu = e.target; 2434 if(menu && menu.matches && menu.matches('.vb-action-dd') && menu.open && isMobile()){ 2435 closeUserPanels(null); 2436 } 2437 }, true); 2438 2439 document.addEventListener('click', function(e){ 2440 if(!closest(e.target, '.post-user') && !closest(e.target, '.vb-action-dd') && !closest(e.target, '.vb-action-menu-panel')){ 2441 syncBodyUserState(); 2442 } 2443 }); 2444 2445 document.addEventListener('keydown', function(e){ 2446 if(e.key === 'Escape'){ 2447 closeUserPanels(null); 2448 document.body.classList.remove('post-user-panel-open'); 2449 } 2450 }); 2451 2452 window.addEventListener('resize', function(){ 2453 if(!isMobile()){ 2454 document.body.classList.remove('post-user-panel-open'); 2455 } else { 2456 syncBodyUserState(); 2457 } 2458 }, {passive:true}); 2459 syncBodyUserState(); 2460})(); 2461 2462/* konu altındaki Bildir/Uyar açılır pencerelerini kapatma */ 2463(function(){ 2464 function closest(node, sel){ return node && node.closest ? node.closest(sel) : null; } 2465 function closePostPopups(except){ 2466 document.querySelectorAll('.post-action-menu[open]').forEach(function(menu){ 2467 if(except && menu === except) return; 2468 if(menu.classList.contains('report-box') || menu.classList.contains('warn-post-menu') || menu.querySelector('.post-pop-form')){ 2469 menu.open = false; 2470 } 2471 }); 2472 } 2473 document.addEventListener('click', function(e){ 2474 var closeBtn = closest(e.target, '[data-post-pop-close]'); 2475 if(closeBtn){ 2476 e.preventDefault(); 2477 var menu = closest(closeBtn, '.post-action-menu'); 2478 if(menu) menu.open = false;
2479 return; 2480 } 2481 var summary = closest(e.target, '.post-action-menu > summary'); 2482 if(summary){ 2483 var menu = closest(summary, '.post-action-menu'); 2484 setTimeout(function(){ closePostPopups(menu && menu.open ? menu : null); }, 0); 2485 return; 2486 } 2487 if(closest(e.target, '.post-pop-form')) return; 2488 if(!closest(e.target, '.post-action-menu')) closePostPopups(null); 2489 }, true); 2490 document.addEventListener('keydown', function(e){ 2491 if(e.key === 'Escape') closePostPopups(null); 2492 }); 2493})(); 2494 2495 2496/* Bildir/Uyar modal dıÅına tıklayınca kesin kapansın */ 2497(function(){ 2498 function closest(node, sel){ return node && node.closest ? node.closest(sel) : null; } 2499 function isPopupMenu(menu){ 2500 return menu && (menu.classList.contains('report-box') || menu.classList.contains('warn-post-menu') || menu.querySelector('.post-pop-form')); 2501 } 2502 function closeMenu(menu){ 2503 if(menu && isPopupMenu(menu)) menu.open = false; 2504 } 2505 document.addEventListener('click', function(e){ 2506 var openMenu = closest(e.target, '.post-action-menu[open]'); 2507 if(!openMenu || !isPopupMenu(openMenu)) return; 2508 if(closest(e.target, '.post-pop-form')) return; 2509 if(closest(e.target, '.post-action-menu > summary')) return; 2510 closeMenu(openMenu); 2511 }, true); 2512})(); 2513 2514/* Bildir/Uyar formlarını body içine taÅı; hiçbir cevap kartı modalın üstüne çıkamaz */ 2515(function(){ 2516 function qs(sel, root){ return (root || document).querySelector(sel); } 2517 function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); } 2518 function closest(node, sel){ return node && node.closest ? node.closest(sel) : null; } 2519 function isMenu(menu){ return menu && (menu.classList.contains('report-box') || menu.classList.contains('warn-post-menu')); } 2520 var active = null; 2521 var backdrop = null; 2522 2523 function ensureBackdrop(){ 2524 if(backdrop && backdrop.parentNode) return backdrop; 2525 backdrop = document.createElement('div'); 2526 backdrop.className = 'post-pop-backdrop'; 2527 backdrop.setAttribute('data-post-pop-backdrop', '1'); 2528 backdrop.addEventListener('click', function(e){ e.preventDefault(); closeActive(); }); 2529 document.body.appendChild(backdrop); 2530 return backdrop; 2531 } 2532 2533 function closeActive(){ 2534 if(!active) return; 2535 var form = active.form; 2536 var menu = active.menu; 2537 if(form){ 2538 form.classList.remove('post-pop-ported'); 2539 form.removeAttribute('data-post-pop-ported'); 2540 if(active.placeholder && active.placeholder.parentNode){ 2541 active.placeholder.parentNode.insertBefore(form, active.placeholder); 2542 active.placeholder.remove(); 2543 } else if(menu){ 2544 menu.appendChild(form); 2545 } 2546 } 2547 if(menu) menu.open = false; 2548 if(backdrop && backdrop.parentNode) backdrop.parentNode.removeChild(backdrop); 2549 document.body.classList.remove('post-pop-portal-open'); 2550 active = null; 2551 } 2552 2553 function openMenu(menu){ 2554 if(!isMenu(menu)) return; 2555 var form = qs('.post-pop-form', menu); 2556 if(!form) return; 2557 if(active && active.menu !== menu) closeActive(); 2558 if(active && active.menu === menu) return; 2559 2560 var placeholder = document.createComment('post-pop-form-placeholder'); 2561 form.parentNode.insertBefore(placeholder, form); 2562 ensureBackdrop(); 2563 document.body.appendChild(form); 2564 form.classList.add('post-pop-ported'); 2565 form.setAttribute('data-post-pop-ported', '1'); 2566 document.body.classList.add('post-pop-portal-open'); 2567 active = { menu: menu, form: form, placeholder: placeholder }; 2568 2569 setTimeout(function(){ 2570 var first = qs('textarea, select, input:not([type="hidden"]), button', form); 2571 if(first && first.focus) first.focus({preventScroll:true}); 2572 }, 40); 2573 } 2574 2575 function closeOtherDetails(except){ 2576 qsa('.post-action-menu[open]').forEach(function(menu){ 2577 if(menu !== except && isMenu(menu)) menu.open = false; 2578 }); 2579 } 2580 2581 document.addEventListener('toggle', function(e){ 2582 var menu = e.target; 2583 if(!isMenu(menu)) return; 2584 if(menu.open){ 2585 closeOtherDetails(menu); 2586 setTimeout(function(){ openMenu(menu); }, 0); 2587 } else if(active && active.menu === menu){ 2588 closeActive(); 2589 } 2590 }, true); 2591 2592 document.addEventListener('click', function(e){
2593 var closeBtn = closest(e.target, '[data-post-pop-close]'); 2594 if(closeBtn && active){ e.preventDefault(); closeActive(); return; } 2595 if(active && closest(e.target, '.post-pop-form.post-pop-ported')) return; 2596 if(active && closest(e.target, '.post-action-menu > summary')) return; 2597 if(active && !closest(e.target, '.post-pop-form.post-pop-ported')){ 2598 var onMenuButton = closest(e.target, '.report-box > summary, .warn-post-menu > summary'); 2599 if(!onMenuButton) closeActive(); 2600 } 2601 }, true); 2602 2603 document.addEventListener('keydown', function(e){ 2604 if(e.key === 'Escape' && active){ e.preventDefault(); closeActive(); } 2605 }); 2606 2607 window.addEventListener('pagehide', closeActive); 2608})(); 2609 2610/* Pazar ürün ekleme görsel seçimi anında önizleme */ 2611(function(){ 2612 function ready(fn){ if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); } 2613 ready(function(){ 2614 document.querySelectorAll('[data-market-image-input]').forEach(function(input){ 2615 input.addEventListener('change', function(){ 2616 var file = input.files && input.files[0] ? input.files[0] : null; 2617 var root = input.closest('[data-market-upload-box]') || input.closest('.market-upload-card') || document; 2618 var nameEl = root.querySelector('[data-market-file-name]'); 2619 var preview = root.querySelector('[data-market-image-preview]'); 2620 if(!file){ if(nameEl) nameEl.textContent = 'JPG, PNG, WEBP veya GIF. BoÅ bırakırsanız mevcut görsel korunur.'; return; } 2621 if(nameEl) nameEl.textContent = file.name + ' seçildi.'; 2622 if(preview && file.type && file.type.indexOf('image/') === 0 && window.FileReader){ 2623 var reader = new FileReader(); 2624 reader.onload = function(e){ preview.innerHTML = '<img src="'+String(e.target.result).replace(/"/g,'"')+'" alt="Seçilen ürün görseli">'; }; 2625 reader.readAsDataURL(file); 2626 } 2627 }); 2628 }); 2629 }); 2630})(); 2631 2632/* kullanıcı reklam formu toplam tutar hesaplama */ 2633(function(){ 2634 function ready(fn){ if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); } 2635 ready(function(){ 2636 document.querySelectorAll('[data-user-ad-form]').forEach(function(form){ 2637 var daily = parseFloat(String(form.getAttribute('data-daily-price') || '0').replace(',', '.')) || 0; 2638 var currency = form.getAttribute('data-currency') || 'TRY'; 2639 var daysInput = form.querySelector('[data-user-ad-days]'); 2640 var totalEl = form.querySelector('[data-user-ad-total]'); 2641 function formatMoney(value){ 2642 try { return new Intl.NumberFormat('tr-TR', {minimumFractionDigits:2, maximumFractionDigits:2}).format(value) + ' ' + currency; } 2643 catch(e){ return value.toFixed(2).replace('.', ',') + ' ' + currency; } 2644 } 2645 function sync(){ 2646 if(!daysInput || !totalEl) return; 2647 var days = parseInt(daysInput.value || '1', 10); 2648 var min = parseInt(daysInput.getAttribute('min') || '1', 10); 2649 var max = parseInt(daysInput.getAttribute('max') || '365', 10); 2650 if(!Number.isFinite(days)) days = min; 2651 days = Math.max(min, Math.min(max, days)); 2652 if(String(daysInput.value) !== String(days)) daysInput.value = String(days); 2653 totalEl.textContent = formatMoney(daily * days); 2654 } 2655 if(daysInput){ daysInput.addEventListener('input', sync); daysInput.addEventListener('change', sync); sync(); } 2656 }); 2657 }); 2658})(); 2659 2660/* Konu etiketleri - Enter ile chip ekleme */ 2661(function(){ 2662 function ready(fn){ if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); } 2663 function normalizeTag(value){ 2664 value = String(value || '').replace(/^#+/, '').replace(/[\r\n;,|]+/g, ' ').replace(/[^\p{L}\p{N}\s_\-.]/gu, '').replace(/\s+/g, ' ').trim(); 2665 if(value.length > 40) value = value.slice(0, 40).trim(); 2666 return value; 2667 } 2668 function slugify(value){ 2669 try { return normalizeTag(value).toLocaleLowerCase('tr-TR').normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/ı/g,'i').replace(/Ä/g,'g').replace(/ü/g,'u').replace(/Å/g,'s').replace(/ö/g,'o').replace(/ç/g,'c').replace(/[^a-z0-9]+/g,'-').replace(/^-+|-+$/g,''); } 2670 catch(e){ return normalizeTag(value).toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/^-+|-+$/g,''); } 2671 } 2672 function setup(root){ 2673 if(!root || root.__topicTagsReady) return; 2674 root.__topicTagsReady = true; 2675 var list = root.querySelector('[data-topic-tag-list]'); 2676 var input = root.querySelector('[data-topic-tag-input]'); 2677 var hidden = root.querySelector('[data-topic-tag-hidden]'); 2678 if(!list || !input || !hidden) return; 2679 var tags = []; 2680 function sync(){ hidden.value = tags.join(','); } 2681 function render(){ 2682 list.innerHTML = '';
2683 tags.forEach(function(tag, index){ 2684 var chip = document.createElement('span'); chip.className = 'topic-tag-chip'; 2685 var text = document.createElement('span'); text.textContent = '#' + tag; chip.appendChild(text); 2686 var btn = document.createElement('button'); btn.type = 'button'; btn.setAttribute('aria-label', tag + ' etiketini kaldır'); btn.textContent = 'Ã'; 2687 btn.addEventListener('click', function(){ tags.splice(index, 1); render(); }); 2688 chip.appendChild(btn); list.appendChild(chip); 2689 }); 2690 sync(); 2691 } 2692 function add(raw){ 2693 String(raw || '').split(/[,;|\n\r]+/).forEach(function(part){ 2694 var tag = normalizeTag(part); if(tag.length < 2) return; 2695 var slug = slugify(tag); if(!slug) return; 2696 var exists = tags.some(function(item){ return slugify(item) === slug; }); 2697 if(!exists && tags.length < 12) tags.push(tag); 2698 }); 2699 render(); 2700 } 2701 var initial = root.getAttribute('data-initial-tags') || hidden.value || ''; 2702 if(initial) add(initial); 2703 input.addEventListener('keydown', function(e){ 2704 if(e.key === 'Enter' || e.key === ',' || e.key === ';'){ 2705 e.preventDefault(); add(input.value); input.value = ''; 2706 } 2707 if(e.key === 'Backspace' && input.value === '' && tags.length){ tags.pop(); render(); } 2708 }); 2709 input.addEventListener('blur', function(){ if(input.value.trim() !== ''){ add(input.value); input.value = ''; } }); 2710 root.closest('form')?.addEventListener('submit', function(){ if(input.value.trim() !== ''){ add(input.value); input.value = ''; } sync(); }); 2711 render(); 2712 } 2713 ready(function(){ document.querySelectorAll('[data-topic-tags]').forEach(setup); }); 2714 document.addEventListener('click', function(){ setTimeout(function(){ document.querySelectorAll('[data-topic-tags]').forEach(setup); }, 0); }); 2715})(); 2716 2717/* profesyonel canlı bildirim sistemi */ 2718(function(){ 2719 function qs(sel, root){ return (root || document).querySelector(sel); } 2720 function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); } 2721 function csrf(){ return document.body ? (document.body.getAttribute('data-csrf-token') || '') : ''; } 2722 function esc(str){ return String(str || '').replace(/[&<>"']/g, function(ch){ return ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]); }); } 2723 function post(url, data){ 2724 if(!url) return Promise.resolve(null); 2725 var fd = new FormData(); 2726 fd.append('_csrf', csrf()); 2727 Object.keys(data || {}).forEach(function(k){ fd.append(k, data[k]); }); 2728 return fetch(url, {method:'POST', body:fd, headers:{'Accept':'application/json','X-Requested-With':'fetch'}, credentials:'same-origin', cache:'no-store'}) 2729 .then(function(r){ return r && r.ok ? r.json() : null; }) 2730 .catch(function(){ return null; }); 2731 } 2732 var previousUnreadCount = null; 2733 var previousLatestNotificationId = 0; 2734 var latestToastId = 0; 2735 var polling = false; 2736 var pollTimer = null; 2737 2738 function notifyToast(item, count){ 2739 if(!item || count <= 0) return; 2740 var id = parseInt(item.id || 0, 10) || 0; 2741 if(id && id === latestToastId) return; 2742 latestToastId = id; 2743 var old = document.querySelector('[data-live-notification-toast]'); 2744 if(old) old.remove(); 2745 var box = document.createElement('a'); 2746 box.setAttribute('data-live-notification-toast','1'); 2747 box.className = 'live-notification-toast-v276'; 2748 box.href = item.url || '#'; 2749 box.innerHTML = '<span class="live-notification-icon">'+esc(item.icon || 'ð')+'</span><strong>'+esc(item.title || 'Yeni bildirim')+'</strong><small>'+esc(item.body || '')+'</small><em>Åimdi</em>'; 2750 document.body.appendChild(box); 2751 window.setTimeout(function(){ box.classList.add('is-visible'); }, 20); 2752 window.setTimeout(function(){ box.classList.remove('is-visible'); window.setTimeout(function(){ if(box.parentNode) box.parentNode.removeChild(box); }, 260); }, 5600); 2753 } 2754 2755 function renderItems(items){ 2756 var list = qs('[data-notification-list]'); 2757 if(!list || !Array.isArray(items)) return; 2758 if(items.length === 0){ 2759 list.innerHTML = '<div class="notification-empty" data-notification-empty>Yeni bildirim yok.</div>'; 2760 return; 2761 } 2762 list.innerHTML = items.map(function(n){ 2763 var id = parseInt(n.id || 0, 10) || 0; 2764 return '<div class="notification-row" data-notification-row data-notification-id="'+id+'">' 2765 + '<a class="notification-item unread" href="'+esc(n.url || '#')+'" data-notification-link data-notification-id="'+id+'">' 2766 + '<span class="notification-dot">'+esc(n.icon || 'ð')+'</span>' 2767 + '<span><strong>'+esc(n.title || 'Bildirim')+'</strong><small>'+esc(n.body || '')+'</small><em>'+esc(n.created_label || n.created_at || '')+'</em></span></a>' 2768 + '<form method="post" action="'+esc(document.body.getAttribute('data-notifications-delete-url') || '')+'" class="notification-delete-form"><input type="hidden" name="_csrf" value="'+esc(csrf())+'"><input type="hidden" name="id" value="'+id+'"><button type="submit" title="Bildirimi sil" aria-label="Bildirimi sil">Ã</button></form>' 2769 + '</div>'; 2770 }).join(''); 2771 } 2772 2773 function updateState(data, options){ 2774 if(!data || !data.ok) return; 2775 options = options || {}; 2776 var count = parseInt(data.unread || 0, 10) || 0; 2777 var items = Array.isArray(data.items) ? data.items : []; 2778 var previousCount = previousUnreadCount; 2779 var newestId = items.length ? (parseInt(items[0].id || 0, 10) || 0) : 0; 2780 var hasNewItem = newestId > 0 && (previousLatestNotificationId > 0 ? newestId > previousLatestNotificationId : (previousCount !== null && count > previousCount)); 2781 if(hasNewItem && !options.silent){ notifyToast(items[0], count); } 2782 var btn = qs('[data-notification-toggle]'); 2783 var badge = qs('[data-notification-count]'); 2784 var label = qs('[data-notification-unread-label]'); 2785 var readForm = qs('[data-notification-read-all-form]'); 2786 if(btn){ 2787 var increased = hasNewItem; 2788 btn.classList.toggle('has-unread', count > 0);
2789 btn.setAttribute('data-unread-count', String(count)); 2790 btn.setAttribute('aria-label', count > 0 ? ('Bildirimler, ' + count + ' okunmamıÅ') : 'Bildirimler'); 2791 if(increased && btn.getAttribute('data-notification-animation') !== '0' && !options.silent){ 2792 btn.classList.remove('is-ringing'); 2793 void btn.offsetWidth; 2794 btn.classList.add('is-ringing'); 2795 window.setTimeout(function(){ btn.classList.remove('is-ringing'); }, 1450); 2796 } 2797 } 2798 if(badge){ badge.textContent = count > 99 ? '99+' : String(count); badge.hidden = count <= 0; } 2799 if(label){ label.textContent = count + ' okunmamıÅ'; } 2800 if(readForm){ readForm.hidden = count <= 0; } 2801 previousUnreadCount = count; 2802 if(newestId > previousLatestNotificationId){ previousLatestNotificationId = newestId; } 2803 renderItems(items); 2804 } 2805 2806 function poll(options){ 2807 var url = document.body ? document.body.getAttribute('data-notifications-poll-url') : ''; 2808 if(!url || !qs('[data-notification-menu]') || polling) return; 2809 polling = true; 2810 fetch(url, {headers:{'Accept':'application/json','Cache-Control':'no-cache','X-Requested-With':'fetch'}, credentials:'same-origin', cache:'no-store'}) 2811 .then(function(r){ return r && r.ok ? r.json() : null; }) 2812 .then(function(data){ updateState(data, options || {}); }) 2813 .catch(function(){}) 2814 .finally(function(){ polling = false; }); 2815 } 2816 function startPolling(){ 2817 if(pollTimer || !qs('[data-notification-menu]')) return; 2818 var initialBtn = qs('[data-notification-toggle]'); 2819 if(previousUnreadCount === null && initialBtn){ 2820 previousUnreadCount = parseInt(initialBtn.getAttribute('data-unread-count') || '0', 10) || 0; 2821 previousLatestNotificationId = parseInt(initialBtn.getAttribute('data-latest-notification-id') || '0', 10) || 0; 2822 } 2823 pollTimer = window.setInterval(function(){ if(!document.hidden) poll(); }, 10000); 2824 } 2825 2826 document.addEventListener('click', function(e){ 2827 var link = e.target.closest('[data-notification-link]'); 2828 if(link){ 2829 var id = link.getAttribute('data-notification-id') || ''; 2830 if(id && window.fetch){ 2831 e.preventDefault(); 2832 var href = link.getAttribute('href') || '#'; 2833 post(document.body.getAttribute('data-notifications-read-url') || '', {id:id}).then(function(data){ updateState(data, {silent:true}); window.location.href = href; }); 2834 window.setTimeout(function(){ if(window.location.href !== href) window.location.href = href; }, 750); 2835 } 2836 return; 2837 } 2838 }, true); 2839 2840 document.addEventListener('submit', function(e){ 2841 var clearForm = e.target.closest('[data-notification-read-all-form],[data-notification-clear-read-form],[data-notification-clear-all-form]'); 2842 if(clearForm && window.fetch){ 2843 e.preventDefault(); 2844 post(clearForm.getAttribute('action'), {}).then(function(data){ updateState(data, {silent:true}); }); 2845 return; 2846 } 2847 var del = e.target.closest('.notification-delete-form'); 2848 if(del && window.fetch){ 2849 e.preventDefault(); 2850 var idEl = qs('input[name="id"]', del); 2851 var row = del.closest('[data-notification-row]'); 2852 if(row){ row.classList.add('is-removing'); } 2853 post(del.getAttribute('action'), {id:idEl ? idEl.value : ''}).then(function(data){ updateState(data, {silent:true}); }); 2854 } 2855 }, true); 2856 2857 document.addEventListener('DOMContentLoaded', startPolling); 2858 window.addEventListener('focus', function(){ poll(); }); 2859 document.addEventListener('visibilitychange', function(){ if(!document.hidden) poll(); }); 2860})(); 2861 2862 2863/* flat yukarı çık butonu */ 2864(function(){ 2865 function ready(fn){ if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); } 2866 ready(function(){ 2867 var btn = document.querySelector('[data-scroll-top]'); 2868 if(!btn) return; 2869 var ticking = false; 2870 function setVisible(){ 2871 var y = window.scrollY || document.documentElement.scrollTop || 0; 2872 var show = y > 420; 2873 btn.hidden = false; 2874 btn.classList.toggle('is-visible', show); 2875 if(!show){ btn.setAttribute('aria-hidden','true'); } else { btn.removeAttribute('aria-hidden'); } 2876 ticking = false;
2877 } 2878 function onScroll(){ 2879 if(!ticking){ window.requestAnimationFrame ? window.requestAnimationFrame(setVisible) : setTimeout(setVisible, 50); ticking = true; } 2880 } 2881 btn.addEventListener('click', function(){ 2882 try { window.scrollTo({top:0, behavior:'smooth'}); } 2883 catch(e){ window.scrollTo(0,0); } 2884 }); 2885 window.addEventListener('scroll', onScroll, {passive:true}); 2886 setVisible(); 2887 }); 2888})(); 2889 2890/* üst flat bildirimler + sayfa yenilemeden uyarma/engelleme + canlı sayaç saÄlamlaÅtırma */ 2891(function(){ 2892 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 2893 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 2894 function token(){ 2895 var bodyToken = document.body ? (document.body.getAttribute('data-csrf-token') || '') : ''; 2896 if(bodyToken) return bodyToken; 2897 var meta = qs('meta[name="csrf-token"]'); 2898 if(meta && meta.content) return meta.content; 2899 var input = qs('input[name="_csrf"], input[name="csrf_token"], input[name="csrf"]'); 2900 return input ? input.value : ''; 2901 } 2902 function ensureAlertStack(){ 2903 var stack = qs('[data-global-alert-stack]'); 2904 if(stack) return stack; 2905 stack = document.createElement('div'); 2906 stack.className = 'global-alert-stack'; 2907 stack.setAttribute('data-global-alert-stack','1'); 2908 stack.setAttribute('aria-live','polite'); 2909 var header = qs('.topbar'); 2910 if(header && header.parentNode) header.parentNode.insertBefore(stack, header.nextSibling); 2911 else document.body.insertBefore(stack, document.body.firstChild); 2912 return stack; 2913 } 2914 function showAlert(type, message){ 2915 type = type || 'success'; 2916 message = message || (type === 'success' ? 'İÅlem tamamlandı.' : 'İÅlem tamamlanamadı.'); 2917 var stack = ensureAlertStack(); 2918 var item = document.createElement('div'); 2919 item.className = 'alert ' + type + ' global-alert-item'; 2920 item.innerHTML = '<span></span><button type="button" data-global-alert-close aria-label="Kapat">
2920Ã</button>'; 2921 item.querySelector('span').textContent = message; 2922 stack.appendChild(item); 2923 window.setTimeout(function(){ item.classList.add('is-hiding'); window.setTimeout(function(){ if(item.parentNode) item.parentNode.removeChild(item); }, 260); }, type === 'danger' ? 6500 : 4200); 2924 } 2925 function isAjaxModerationForm(form){ 2926 if(!form || form.hasAttribute('data-no-ajax')) return false; 2927 var action = form.getAttribute('action') || ''; 2928 return /\/post\/\d+\/warn(?:$|[?#])/i.test(action) 2929 || /\/post\/\d+\/user-action(?:$|[?#])/i.test(action) 2930 || /\/admin\/warnings\/create(?:$|[?#])/i.test(action) 2931 || /\/admin\/users\/status(?:$|[?#])/i.test(action); 2932 } 2933 function closeModerationUi(form){ 2934 qsa('details[open]', form.closest('.post-action-menu,.post-admin-user-subform,.admin-timed-ban-menu,.admin-user-more-menu') || form).forEach(function(d){ d.open = false; }); 2935 var details = form.closest('details'); if(details) details.open = false; 2936 var warnModal = form.closest('[data-admin-warn-modal]'); 2937 if(warnModal){ warnModal.hidden = true; document.body.classList.remove('admin-warn-open'); } 2938 var vbModal = form.closest('[data-vb-modal]'); 2939 if(vbModal){ vbModal.hidden = true; vbModal.setAttribute('aria-hidden','true'); document.body.classList.remove('vb-modal-open'); } 2940 } 2941 function updateUserStatusCard(form, payload){ 2942 var action = form.getAttribute('action') || ''; 2943 if(action.indexOf('/admin/users/status') === -1) return; 2944 var statusInput = qs('input[name="status"]', form); 2945 var status = (payload && payload.status) || (statusInput ? statusInput.value : ''); 2946 if(!status) return; 2947 var card = form.closest('.admin-user-card'); 2948 if(!card) return; 2949 var labels = {active:'Aktif', blocked:'Engelli', pending:'Onay bekliyor'}; 2950 var classes = {active:'ok', blocked:'off', pending:'warn'}; 2951 var badge = null; 2952 qsa('.admin-user-title .badge', card).some(function(b){ 2953 if((b.textContent || '').trim() !== 'Sen'){ badge = b; return true; } 2954 return false; 2955 }); 2956 if(badge){ 2957 badge.className = 'badge ' + (classes[status] || 'off'); 2958 badge.textContent = labels[status] || status; 2959 } 2960 card.classList.add('ajax-status-updated'); 2961 } 2962 function markSubmitted(form, payload){ 2963 var button = qs('button[type="submit"], button:not([type])', form); 2964 if(button && payload && payload.ok){ 2965 button.setAttribute('data-original-label', button.getAttribute('data-original-label') || button.textContent); 2966 button.textContent = 'â İÅlem yapıldı'; 2967 window.setTimeout(function(){ 2968 var original = button.getAttribute('data-original-label'); 2969 if(original) button.textContent = original; 2970 }, 2400); 2971 } 2972 var article = form.closest('[data-vb-post], .post.card, .admin-user-card'); 2973 if(article && payload && payload.ok) article.classList.add('ajax-action-done'); 2974 } 2975 document.addEventListener('click', function(e){ 2976 var close = e.target.closest('[data-global-alert-close]'); 2977 if(close){ 2978 e.preventDefault(); 2979 var item = close.closest('.global-alert-item,.alert'); 2980 if(item && item.parentNode) item.parentNode.removeChild(item); 2981 } 2982 }); 2983 document.addEventListener('submit', function(e){ 2984 var form = e.target; 2985 if(!isAjaxModerationForm(form)) return; 2986 if(e.defaultPrevented) return; 2987 e.preventDefault(); 2988 var submitter = e.submitter || qs('button[type="submit"], button:not([type])', form); 2989 var oldText = submitter ? submitter.textContent : ''; 2990 if(submitter){ submitter.disabled = true; submitter.textContent = 'İÅleniyor...'; } 2991 var fd = new FormData(form); 2992 fd.set('ajax', '1'); 2993 var t = token(); 2994 if(t && !fd.has('_csrf')) fd.set('_csrf', t); 2995 fetch(form.action, { 2996 method: 'POST', 2997 body: fd, 2998 credentials: 'same-origin', 2999 cache: 'no-store', 3000 headers: {'Accept':'application/json','X-Requested-With':'XMLHttpRequest'} 3001 }).then(function(res){ 3002 return res.text().then(function(text){ 3003 var payload = null; 3004 try { payload = text ? JSON.parse(text) : null; } catch(err) {} 3005 if(!payload) payload = {ok:res.ok, type:res.ok?'success':'danger', message:res.ok?'İÅlem tamamlandı.':'İÅlem tamamlanamadı.'}; 3006 payload.httpOk = res.ok; 3007 return payload; 3008 }); 3009 }).then(function(payload){ 3010 var ok = !!(payload && payload.ok); 3011 showAlert(ok ? (payload.type || 'success') : 'danger', payload && payload.message ? payload.message : (ok ? 'İÅlem tamamlandı.' : 'İÅlem tamamlanamadı.')); 3012 if(ok){ 3013 closeModerationUi(form); 3014 updateUserStatusCard(form, payload); 3015 markSubmitted(form, payload); 3016 try { form.reset(); } catch(err) {} 3017 } 3018 }).catch(function(){ 3019 showAlert('danger', 'BaÄlantı hatası oluÅtu. İÅlem tamamlanamadı.'); 3020 }).finally(function(){ 3021 if(submitter){ submitter.disabled = false; if(oldText) submitter.textContent = oldText; } 3022 }); 3023 }); 3024 document.addEventListener('DOMContentLoaded', function(){ 3025 window.setTimeout(function(){
3026 try { window.dispatchEvent(new CustomEvent('wmt:live-refresh-request')); } catch(e) {} 3027 }, 900); 3028 }); 3029})(); 3030 3031/* canlı destek sohbeti + sade Yazıyor... göstergesi */ 3032(function(){ 3033 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 3034 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 3035 function esc(v){ return String(v == null ? '' : v).replace(/[&<>"']/g, function(ch){ return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]; }); } 3036 function csrf(){ var b=document.body; var t=b ? b.getAttribute('data-csrf-token') : ''; if(t) return t; var i=qs('input[name="_csrf"]'); return i ? i.value : ''; } 3037 function avatarHtml(m){ 3038 var av = String(m.avatar || '').trim(); 3039 if(av){ if(!/^https?:\/\//i.test(av) && av.charAt(0) !== '/'){ var scope = (document.body && document.body.getAttribute('data-pwa-scope')) || '/'; av = scope.replace(/\/?$/, '/') + av.replace(/^\/+/, ''); } return '<img src="'+esc(av)+'" alt="'+esc(m.username || '')+'">'; } 3040 return '<b>'+esc(String(m.username || 'U').charAt(0).toUpperCase())+'</b>'; 3041 } 3042 function renderMessage(m, currentId){ 3043 var mine = parseInt(m.sender_id || 0, 10) === currentId; 3044 var internal = String(m.visibility || 'public') === 'internal'; 3045 return '<div class="support-message '+(mine?'mine ':'')+(internal?'internal':'')+'" data-message-id="'+esc(m.id)+'">' 3046 + '<span class="support-message-avatar">'+avatarHtml(m)+'</span>' 3047 + '<div class="support-message-bubble"><div class="support-message-meta"><strong>'+esc(m.username || 'Kullanıcı')+'</strong><small>'+esc(m.created_at || '')+'</small>'+(internal?'<em>İç not</em>':'')+'</div><div class="support-message-body">'+esc(m.body || '').replace(/\n/g,'<br>')+'</div></div>' 3048 + '</div>'; 3049 } 3050 function setup(chat){ 3051 var list = qs('[data-support-messages]', chat), form = qs('[data-support-reply-form]', chat), typing = qs('[data-support-typing]', chat), historyBtn = qs('[data-support-load-older]', chat); 3052 if(!list || !form) return; 3053 var currentId = parseInt(chat.getAttribute('data-current-user-id') || '0', 10); 3054 var pollUrl = chat.getAttribute('data-poll-url') || ''; 3055 var typingUrl = chat.getAttribute('data-typing-url') || ''; 3056 var lastId = parseInt(form.getAttribute('data-last-id') || '0', 10); 3057 var textarea = qs('textarea[name="body"]', form); 3058 var typingTimer = 0; 3059 function setTyping(rows){ if(!typing) return; typing.hidden = !(rows && rows.length); typing.textContent = 'Yazıyor...'; } 3060 function append(messages){ 3061 if(!messages || !messages.length) return; 3062 var html = ''; 3063 messages.forEach(function(m){ var mid = parseInt(m.id || 0, 10); if(mid > lastId && !qs('[data-message-id="'+mid+'"]', list)){ html += renderMessage(m, currentId); lastId = Math.max(lastId, mid); } }); 3064 if(html){ list.insertAdjacentHTML('beforeend', html); form.setAttribute('data-last-id', String(lastId)); list.scrollTop = list.scrollHeight; } 3065 } 3066 function prependHistory(messages){ 3067 if(!messages || !messages.length) return; 3068 var html = '', beforeHeight = list.scrollHeight; 3069 messages.forEach(function(m){ var mid=parseInt(m.id||0,10); if(mid>0 && !qs('[data-message-id="'+mid+'"]', list)){ html += renderMessage(m,currentId); } }); 3070 if(html){ list.insertAdjacentHTML('afterbegin', html); list.scrollTop += (list.scrollHeight - beforeHeight); } 3071 } 3072 if(historyBtn){ 3073 historyBtn.addEventListener('click', function(){ 3074 var base=historyBtn.getAttribute('data-history-url')||'', before=parseInt(historyBtn.getAttribute('data-before-id')||'0',10); if(!base||before<=0) return; 3075 var oldText=historyBtn.textContent; historyBtn.disabled=true; historyBtn.textContent='Yükleniyor...'; 3076 fetch(base + (base.indexOf('?')===-1?'?':'&') + 'before_id=' + encodeURIComponent(before), {credentials:'same-origin',cache:'no-store',headers:{'Accept':'application/json','X-Requested-With':'XMLHttpRequest'}}) 3077 .then(function(r){ return r.json(); }).then(function(p){ if(!p||!p.ok){ throw new Error((p&&p.message)||'GeçmiŠyüklenemedi.'); }
3077 prependHistory(p.messages||[]); var next=parseInt(p.oldest_id||0,10); if(next>0) historyBtn.setAttribute('data-before-id',String(next)); if(!p.has_more || !(p.messages||[]).length){ historyBtn.hidden=true; } }) 3078 .catch(function(){ historyBtn.textContent='Tekrar dene'; window.setTimeout(function(){ if(!historyBtn.hidden) historyBtn.textContent=oldText||'â Daha eski mesajları yükle'; },1800); }) 3079 .finally(function(){ historyBtn.disabled=false; }); 3080 }); 3081 } 3082 function poll(){ 3083 if(!pollUrl) return; 3084 fetch(pollUrl + (pollUrl.indexOf('?') === -1 ? '?' : '&') + 'after_id=' + encodeURIComponent(lastId), {credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json','X-Requested-With':'XMLHttpRequest'}}) 3085 .then(function(r){ return r.json(); }).then(function(p){ if(!p || !p.ok) return; append(p.messages || []); setTyping(p.typing || []); var st=qs('[data-support-status]'); if(st && p.ticket_status){ st.textContent = p.ticket_status; } }).catch(function(){}); 3086 } 3087 if(textarea && typingUrl){ 3088 textarea.addEventListener('input', function(){ 3089 var now = Date.now(); if(now - typingTimer < 2200) return; typingTimer = now; 3090 var fd = new FormData(); fd.set('_csrf', csrf()); fd.set('ajax','1'); 3091 fetch(typingUrl, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json','X-Requested-With':'XMLHttpRequest'}}).catch(function(){}); 3092 }); 3093 } 3094 form.addEventListener('submit', function(e){ 3095 e.preventDefault(); 3096 var btn = qs('button[type="submit"]', form); var old = btn ? btn.textContent : ''; 3097 if(btn){ btn.disabled = true; btn.textContent = 'Gönderiliyor...'; } 3098 var fd = new FormData(form); fd.set('ajax','1'); if(!fd.has('_csrf')) fd.set('_csrf', csrf()); 3099 fetch(form.action, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json','X-Requested-With':'XMLHttpRequest'}}) 3100 .then(function(r){ return r.json(); }).then(function(p){ if(p && p.ok){ append(p.messages || []); if(textarea) textarea.value=''; setTyping([]); } else { alert((p && p.message) || 'Mesaj gönderilemedi.'); } }) 3101 .catch(function(){ alert('BaÄlantı hatası oluÅtu.'); }) 3102 .finally(function(){ if(btn){ btn.disabled = false; btn.textContent = old || 'Gönder'; } }); 3103 }); 3104 list.scrollTop = list.scrollHeight; 3105 window.setInterval(poll, 3500); 3106 poll(); 3107 } 3108 document.addEventListener('DOMContentLoaded', function(){ qsa('[data-support-chat]').forEach(setup); }); 3109})(); 3110 3111/* Pazar profesyonel ürün formu - dijital/fiziksel akıŠve dosya adı */ 3112(function(){ 3113 function ready(fn){ if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); } 3114 ready(function(){ 3115 document.querySelectorAll('[data-market-product-form]').forEach(function(form){ 3116 var typeInputs = Array.prototype.slice.call(form.querySelectorAll('[data-market-type-input]')); 3117 var digitalSection = form.querySelector('[data-market-digital-section]'); 3118 var physicalSection = form.querySelector('[data-market-physical-section]'); 3119 var stockField = form.querySelector('[data-market-stock-field]'); 3120 var digitalCheck = form.querySelector('[data-market-check-digital]'); 3121 var physicalCheck = form.querySelector('[data-market-check-physical]'); 3122 function currentType(){ 3123 var checked = typeInputs.find(function(input){ return input.checked; }); 3124 return checked ? checked.value : 'digital'; 3125 } 3126 function syncType(){ 3127 var type = currentType(); 3128 form.querySelectorAll('[data-market-type-card]').forEach(function(card){ 3129 var input = card.querySelector('[data-market-type-input]'); 3130 card.classList.toggle('active', !!input && input.checked); 3131 }); 3132 var isDigital = type === 'digital'; 3133 if(digitalSection) digitalSection.hidden = !isDigital; 3134 if(physicalSection) physicalSection.hidden = isDigital; 3135 if(stockField){ 3136 var first = stockField.firstChild;
3137 if(first && first.nodeType === 3) first.nodeValue = isDigital ? 'Lisans / indirme adedi' : 'Stok / adet'; 3138 } 3139 if(digitalCheck) digitalCheck.style.display = isDigital ? '' : 'none'; 3140 if(physicalCheck) physicalCheck.style.display = isDigital ? 'none' : ''; 3141 } 3142 typeInputs.forEach(function(input){ input.addEventListener('change', syncType); }); 3143 syncType(); 3144 3145 var digitalFile = form.querySelector('[data-market-digital-file-input]'); 3146 if(digitalFile){ 3147 digitalFile.addEventListener('change', function(){ 3148 var file = digitalFile.files && digitalFile.files[0] ? digitalFile.files[0] : null; 3149 var box = digitalFile.closest('[data-market-digital-file-box]') || form; 3150 var nameEl = box.querySelector('[data-market-digital-file-name]'); 3151 if(nameEl){ nameEl.textContent = file ? (file.name + ' seçildi.') : 'ZIP, PDF, görsel, video, doküman veya arÅiv yükleyin.'; } 3152 }); 3153 } 3154 }); 3155 }); 3156})(); 3157 3158/* webmaster konu asistanı ve profil seçimleri */ 3159(function(){ 3160 function qs(sel, ctx){ return (ctx||document).querySelector(sel); } 3161 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx||document).querySelectorAll(sel)); } 3162 function insertTemplate(textarea, text){ 3163 if(!textarea) return; 3164 var current = textarea.value || ''; 3165 var add = text.trim(); 3166 if(current.trim() !== ''){ 3167 if(!window.confirm('Mevcut mesajın sonuna seçilen webmaster Åablonu eklensin mi?')) return; 3168 textarea.value = current.replace(/\s+$/,'') + '\n\n' + add + '\n'; 3169 } else { 3170 textarea.value = add + '\n'; 3171 } 3172 textarea.focus(); 3173 textarea.setSelectionRange(textarea.value.length, textarea.value.length); 3174 textarea.dispatchEvent(new Event('input',{bubbles:true})); 3175 } 3176 var templates = { 3177 'site-error': '[h2]Sorun Ãzeti[/h2]\nSite hangi sayfada hata veriyor?\n\n[h2]AldıÄım Hata[/h2]\nHata kodu / ekran çıktısı:\n\n[code]\nBuraya hata mesajını yapıÅtırın\n[/code]\n\n[h2]Ne Denedim?[/h2]\n- Cache temizledim\n- Eklenti/tema kontrol ettim\n- Log dosyasına baktım\n\n[h2]Yardım İstediÄim Nokta[/h2]\n', 3178 'seo': '[h2]SEO Sorunu[/h2]\nKonu: indexleme / sitemap / meta / canonical / hız / schema\n\n[h2]Site Bilgisi[/h2]\nSite adresi:\n\n[h2]Google Search Console Durumu[/h2]\n- Hata mesajı:\n- Etkilenen sayfa sayısı:\n\n[h2]Ne Yapılmasını İstiyorum?[/h2]\n', 3179 'server': '[h2]Sunucu / Hosting Bilgisi[/h2]\nPanel: cPanel / Plesk / DirectAdmin / VPS\nPHP sürümü:\nVeritabanı:\n\n[h2]Sorun[/h2]\n\n[h2]Log / Hata Ãıktısı[/h2]\n[code]\nBuraya log veya hata mesajı\n[/code]\n\n[h2]Yardım BeklediÄim Konu[/h2]\n', 3180 'security': '[h2]Güvenlik Bildirimi[/h2]\nSorun türü: bot / spam / açık / zararlı istek / dosya deÄiÅikliÄi\n\n[h2]Belirti[/h2]\n\n[h2]AldıÄım Ãnlem[/h2]\n- Åifreleri yeniledim\n- Dosya izinlerini kontrol ettim\n- Logları inceledim\n\n[h2]İncelenmesi Gereken Alan[/h2]\n', 3181 'project': '[h2]İhtiyaç Ãzeti[/h2]\nNe yaptırmak istiyorum?\n\n[h2]Teknik Gereksinimler[/h2]\n- PHP sürümü:\n- Panel / altyapı:\n- Mobil uyum:\n\n[h2]Bütçe / Teslim Süresi[/h2]\n\n[h2]Ek Notlar[/h2]\n' 3182 }; 3183 document.addEventListener('click', function(e){ 3184 var btn = e.target.closest('[data-webmaster-template]'); 3185 if(!btn) return; 3186 e.preventDefault(); 3187 var form = btn.closest('form') || document; 3188 var ta = qs('[data-ffp-editor] textarea', form); 3189 insertTemplate(ta, templates[btn.getAttribute('data-webmaster-template')] || ''); 3190 }); 3191 document.addEventListener('change', function(e){ 3192 var issue = e.target.closest('input[name="webmaster_issue_type"]'); 3193 if(issue){ 3194 qsa('.webmaster-issue-card', issue.closest('.webmaster-issue-grid') || document).forEach(function(card){ card.classList.toggle('is-selected', !!qs('input:checked', card)); }); 3195 } 3196 var skill = e.target.closest('.webmaster-skill-choice input'); 3197 if(skill){ 3198 var card = skill.closest('.webmaster-skill-choice'); 3199 if(card) card.classList.toggle('is-selected', skill.checked); 3200 } 3201 }); 3202})(); 3203 3204 3205 3206 3207/* geliÅmiÅ blog SEO paneli, kod kopyalama ve kompakt baÅlık seçimi */ 3208(function(){ 3209 function qs(sel, ctx){ return (ctx||document).querySelector(sel); } 3210 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx||document).querySelectorAll(sel)); } 3211 function plain(v){ return String(v||'').replace(/\[[^\]]+\]/g,' ').replace(/\s+/g,' ').trim(); } 3212 function words(v){ var m=plain(v).match(/\S+/g); return m?m.length:0; } 3213 function setChecks(form){ 3214 var title=qs('[data-blog-seo-title]',form), excerpt=qs('[data-blog-seo-excerpt]',form), body=qs('[data-blog-seo-body]',form); 3215 var metaTitle=qs('[data-blog-meta-title]',form), metaDesc=qs('[data-blog-meta-description]',form), metaKeys=qs('[data-blog-meta-keywords]',form); 3216 var checks=[], score=100; 3217 var t=(metaTitle&&metaTitle.value.trim()) || (title&&title.value.trim()) || ''; 3218 var d=(metaDesc&&metaDesc.value.trim()) || (excerpt&&excerpt.value.trim()) || plain(body&&body.value).slice(0,160); 3219 var b=(body&&body.value)||''; 3220 var k=(metaKeys&&metaKeys.value.trim())||''; 3221 function add(ok, good, bad, penalty){ if(ok){ checks.push('<div class="ok">â '+good+'</div>'); } else { score-=penalty||10; checks.push('<div class="warn">! '+bad+'</div>'); } } 3222 add(t.length>=30 && t.length<=70, 'Meta baÅlık uzunluÄu uygun.', 'Meta baÅlık 30-70 karakter aralıÄında olmalı.', 15); 3223 add(d.length>=80 && d.length<=160, 'Meta açıklama uzunluÄu uygun.', 'Meta açıklama 80-160 karakter aralıÄında olmalı.', 15); 3224 add(/\[h[123]\]/i.test(b), 'Yazıda baÅlık yapısı var.', 'İçerikte BaÅlık 2/3 kullanılması önerilir.', 12); 3225 add(words(b)>=120, 'İçerik uzunluÄu iyi görünüyor.', 'İçeriÄi biraz daha detaylandırın.', 12); 3226 add(k.length>0 || words(b)>20, 'Anahtar kelime alanı hazır/üretilebilir.', 'Anahtar kelime alanı boÅ.', 8); 3227 add(/\[code\]|\[url=|https?:\/\//i.test(b), 'Kod veya baÄlantı gibi destekleyici içerik var.', 'Kod/baÄlantı örneÄi eklemek faydalı olabilir.', 5); 3228 score=Math.max(0,Math.min(100,score)); 3229 var scoreEl=qs('[data-blog-seo-score]',form); if(scoreEl) scoreEl.textContent=score; 3230 var wrap=qs('[data-blog-seo-score-wrap]',form); if(wrap){ wrap.classList.toggle('is-good', score>=75); wrap.classList.toggle('is-mid', score>=50 && score<75); wrap.classList.toggle('is-low', score<50); } 3231 var panel=qs('[data-blog-seo-checks]',form); if(panel) panel.innerHTML=checks.join(''); 3232 } 3233 function initSeo(){ qsa('[data-blog-seo-form]').forEach(function(form){ setChecks(form); form.addEventListener('input', function(){ setChecks(form); }); }); } 3234 function copyCode(btn){ 3235 var box=btn.closest('.forum-code-block'); if(!box) return; 3236 var code=qs('code',box); var text=code ? code.innerText : ''; 3237 if(!text) return; 3238 var done=function(){ var old=btn.textContent; btn.textContent='Kopyalandı'; setTimeout(function(){btn.textContent=old||'Kopyala';},1600); }; 3239 if(navigator.clipboard && navigator.clipboard.writeText){ navigator.clipboard.writeText(text).then(done).catch(done); } 3240 else { var ta=document.createElement('textarea'); ta.value=text; document.body.appendChild(ta); ta.select(); try{ document.execCommand('copy'); }catch(e){} ta.remove(); done(); } 3241 } 3242 document.addEventListener('click', function(e){ var b=e.target.closest('[data-code-copy]'); if(b){ e.preventDefault(); e.stopPropagation(); copyCode(b); } }); 3243 document.addEventListener('DOMContentLoaded', initSeo); 3244})(); 3245 3246 3247 3248 3249/* Blog kategori düzenleme satırını eriÅilebilir biçimde aç. */ 3250(function(){ 3251 document.addEventListener('click', function(e){ 3252 var edit=e.target && e.target.closest ? e.target.closest('[data-blog-category-edit-trigger]') : null; 3253 if(!edit) return; 3254 e.preventDefault(); 3255 var row=edit.closest('details'); 3256 if(row) row.open=true; 3257 }); 3258})(); 3259 3260 3261 3262 3263/* Mobil site menüsü tek saÄ Ã§ekmece kontrolcüsü - boÅ alan açma ve soldan açılma düzeltildi */ 3264(function(){ 3265 var BP = 850; 3266 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 3267 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 3268 function isMobile(){ return !window.matchMedia || window.matchMedia('(max-width: '+BP+'px)').matches; } 3269 function nav(){ return document.getElementById('mobileMainNav') || qs('[data-mobile-main-nav]'); }
3270 function toggle(){ return qs('[data-mobile-menu-toggle]'); } 3271 function backdrop(){ 3272 var b = qs('.mobile-menu-backdrop'); 3273 if(!b){ 3274 b = document.createElement('button'); 3275 b.type = 'button'; 3276 b.className = 'mobile-menu-backdrop'; 3277 b.setAttribute('aria-label','Menüyü kapat'); 3278 b.setAttribute('tabindex','-1'); 3279 document.body.appendChild(b); 3280 } 3281 return b; 3282 } 3283 function hardRight(n){ 3284 if(!n) return; 3285 n.style.position = 'fixed'; 3286 n.style.top = '0'; 3287 n.style.right = '0'; 3288 n.style.bottom = '0'; 3289 n.style.left = 'auto'; 3290 n.style.inset = '0 0 0 auto'; 3291 n.style.filter = 'none'; 3292 n.style.webkitFilter = 'none'; 3293 n.style.backdropFilter = 'none'; 3294 n.style.webkitBackdropFilter = 'none'; 3295 } 3296 function mount(){ 3297 var n = nav(); 3298 var b = backdrop(); 3299 if(b.parentElement !== document.body) document.body.appendChild(b); 3300 if(n){ 3301 if(n.parentElement !== document.body) document.body.appendChild(n); 3302 hardRight(n); 3303 } 3304 return n; 3305 } 3306 function closeHeaderDropdowns(){ 3307 qsa('[data-user-menu].open,[data-notification-menu].open,[data-language-menu].open').forEach(function(m){ 3308 m.classList.remove('open'); 3309 qsa('[aria-expanded]', m).forEach(function(btn){ btn.setAttribute('aria-expanded','false'); }); 3310 }); 3311 } 3312 function setButton(open){ 3313 var t = toggle(); 3314 if(t){ 3315 t.setAttribute('aria-expanded', open ? 'true' : 'false'); 3316 t.setAttribute('aria-label', open ? 'Site menüsünü kapat' : 'Site menüsünü aç'); 3317 t.title = open ? 'Site menüsünü kapat' : 'Site menüsü'; 3318 } 3319 } 3320 function openMenu(){ 3321 var n = mount(); 3322 if(!n) return; 3323 closeHeaderDropdowns(); 3324 hardRight(n); 3325 n.classList.add('open','is-open'); 3326 n.removeAttribute('hidden'); 3327 n.setAttribute('aria-hidden','false'); 3328 n.style.visibility = 'visible'; 3329 n.style.opacity = '1'; 3330 n.style.pointerEvents = 'auto'; 3331 n.style.transform = 'translate3d(0,0,0)'; 3332 backdrop().classList.add('is-open'); 3333 document.body.classList.add('mobile-main-nav-open','wmt-site-menu-open'); 3334 document.body.classList.remove('nav-open'); 3335 setButton(true); 3336 } 3337 function closeMenu(){ 3338 var n = nav(); 3339 if(n){ 3340 hardRight(n); 3341 n.classList.remove('open','is-open'); 3342 n.setAttribute('aria-hidden','true'); 3343 n.style.visibility = 'hidden'; 3344 n.style.opacity = '1'; 3345 n.style.pointerEvents = 'none'; 3346 n.style.transform = 'translate3d(112%,0,0)'; 3347 } 3348 var b = qs('.mobile-menu-backdrop'); 3349 if(b) b.classList.remove('is-open'); 3350 document.body.classList.remove('mobile-main-nav-open','wmt-site-menu-open','nav-open'); 3351 setButton(false); 3352 } 3353 function isOpen(){ 3354 var n = nav(); 3355 return !!(n && (n.classList.contains('open') || n.classList.contains('is-open') || document.body.classList.contains('wmt-site-menu-open') || document.body.classList.contains('mobile-main-nav-open'))); 3356 } 3357 function toggleMenu(){ isOpen() ? closeMenu() : openMenu(); } 3358 function init(){ mount(); closeMenu(); } 3359 if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, {once:true}); else init(); 3360 3361 window.addEventListener('click', function(e){ 3362 if(!isMobile()) return; 3363 var t = e.target && e.target.closest ? e.target.closest('[data-mobile-menu-toggle]') : null; 3364 if(t){ 3365 e.preventDefault(); 3366 e.stopPropagation(); 3367 if(e.stopImmediatePropagation) e.stopImmediatePropagation(); 3368 toggleMenu(); 3369 return; 3370 } 3371 var close = e.target && e.target.closest ? e.target.closest('[data-nav-close], .mobile-menu-backdrop') : null; 3372 if(close){ 3373 if(isOpen()){ 3374 e.preventDefault(); 3375 e.stopPropagation(); 3376 if(e.stopImmediatePropagation) e.stopImmediatePropagation(); 3377 closeMenu(); 3378 } 3379 return; 3380 } 3381 if(isOpen()){ 3382 var n = nav(); 3383 var inside = e.target && e.target.closest ? e.target.closest('#mobileMainNav') : null; 3384 var link = e.target && e.target.closest ? e.target.closest('#mobileMainNav a') : null; 3385 if(link){ closeMenu(); return; } 3386 if(n && !inside){ 3387 e.preventDefault(); 3388 e.stopPropagation(); 3389 if(e.stopImmediatePropagation) e.stopImmediatePropagation(); 3390 closeMenu(); 3391 } 3392 } 3393 }, true); 3394 3395 window.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeMenu(); }, true); 3396 window.addEventListener('resize', function(){ if(!isMobile()) closeMenu(); }, {passive:true}); 3397})(); 3398
3399/* blog kapak resmi anında yükleme + kullanıcı bazlı geliÅmiÅ görsel akıÅı */ 3400(function(){ 3401 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 3402 function body(){ return document.body || document.documentElement; } 3403 function esc(value){ return String(value == null ? '' : value).replace(/[&<>"']/g, function(ch){ return ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]); }); } 3404 function status(form, message, type){ 3405 var out = qs('[data-blog-cover-status]', form); 3406 if(!out) return; 3407 out.textContent = message || ''; 3408 out.className = 'blog-cover-upload-status-v238 ' + (type || ''); 3409 } 3410 function setPreview(form, url){ 3411 var preview = qs('[data-blog-cover-preview]', form); 3412 if(!preview || !url) return; 3413 preview.innerHTML = '<img src="'+esc(url)+'" alt="Blog kapak görseli" loading="lazy">'; 3414 preview.classList.add('has-image'); 3415 } 3416 function uploadCover(input){ 3417 var form = input.closest('[data-blog-cover-form]'); 3418 if(!form || !input.files || !input.files.length) return; 3419 var file = input.files[0]; 3420 if(!file || !/^image\//i.test(file.type || '')){ status(form, 'Lütfen geçerli bir resim seçin.', 'error'); return; } 3421 var uploadUrl = body().getAttribute('data-blog-cover-upload-url') || ''; 3422 var token = body().getAttribute('data-csrf-token') || ''; 3423 var hidden = qs('[data-blog-cover-path]', form); 3424 var remove = qs('[data-blog-cover-remove]', form); 3425 if(!uploadUrl){ status(form, 'Kapak yükleme adresi bulunamadı.', 'error'); return; } 3426 var fd = new FormData(); 3427 fd.append('_csrf', token); 3428 fd.append('cover_image', file); 3429 status(form, 'Kapak resmi yükleniyor...', 'loading'); 3430 input.disabled = true; 3431 fetch(uploadUrl, {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){ 3432 return r.json().catch(function(){ return {ok:false,message:'Sunucu yanıtı okunamadı.'}; }); 3433 }).then(function(payload){ 3434 if(!payload || !payload.ok){ throw new Error((payload && payload.message) ? payload.message : 'Kapak resmi yüklenemedi.'); } 3435 if(hidden) hidden.value = payload.path || ''; 3436 if(remove) remove.checked = false; 3437 if(payload.url) setPreview(form, payload.url); 3438 input.value = ''; 3439 status(form, payload.message || 'Kapak resmi yüklendi ve önizlemeye eklendi.', 'success'); 3440 }).catch(function(err){ 3441 status(form, (err && err.message) ? err.message : 'Kapak resmi yüklenemedi.', 'error'); 3442 }).finally(function(){ input.disabled = false; }); 3443 } 3444 document.addEventListener('change', function(e){ 3445 var input = e.target.closest('[data-blog-cover-input]'); 3446 if(input){ uploadCover(input); } 3447 var remove = e.target.closest('[data-blog-cover-remove]'); 3448 if(remove && remove.checked){ 3449 var form = remove.closest('[data-blog-cover-form]'); 3450 var hidden = form ? qs('[data-blog-cover-path]', form) : null; 3451 if(hidden) hidden.value = ''; 3452 status(form, 'Kapak resmi kayıt sırasında kaldırılacak.', ''); 3453 } 3454 }); 3455})(); 3456 3457/* Blog editörüne güvenli HTML yapıÅtırma ve HTML ekleme penceresi */ 3458(function(){ 3459 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 3460 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 3461 function body(){ return document.body || document.documentElement; } 3462 function esc(value){ return String(value == null ? '' : value).replace(/[&<>"']/g, function(ch){ return ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]); }); } 3463 function cleanSpace(value){ return String(value || '').replace(/\u00a0/g, ' ').replace(/[ \t]+\n/g, '\n').replace(/\n[ \t]+/g, '\n'); } 3464 function allowedUrl(url){ 3465 url = String(url || '').trim(); 3466 if(!url) return ''; 3467 if(/^javascript:/i.test(url) || /^data:/i.test(url)) return ''; 3468 if(/^https?:\/\//i.test(url) || /^\//.test(url) || /^storage\/uploads\/(editor|blog)\//i.test(url)) return url; 3469 return ''; 3470 } 3471 function textOf(node){ return cleanSpace(node ? (node.textContent || '') : ''); } 3472 function childrenToMarkup(node){ 3473 var out = '';
3474 Array.prototype.slice.call(node.childNodes || []).forEach(function(child){ out += nodeToMarkup(child); }); 3475 return out; 3476 } 3477 function listToMarkup(node, ordered){ 3478 var lines = []; 3479 var i = 1; 3480 Array.prototype.slice.call(node.children || []).forEach(function(li){ 3481 if(!li || String(li.tagName || '').toLowerCase() !== 'li') return; 3482 var prefix = ordered ? (i++ + '. ') : '- '; 3483 var line = childrenToMarkup(li).replace(/\n{2,}/g, '\n').trim(); 3484 if(line) lines.push(prefix + line.replace(/\n/g, '\n ')); 3485 }); 3486 return lines.length ? ('\n' + lines.join('\n') + '\n') : ''; 3487 } 3488 function tableToMarkup(node){ 3489 var rows = []; 3490 qsa('tr', node).forEach(function(tr){ 3491 var cells = []; 3492 qsa('th,td', tr).forEach(function(td){ cells.push(textOf(td).replace(/\s+/g, ' ').trim()); }); 3493 if(cells.length) rows.push('| ' + cells.join(' | ') + ' |'); 3494 }); 3495 return rows.length ? ('\n[code]\n' + rows.join('\n') + '\n[/code]\n') : ''; 3496 } 3497 function nodeToMarkup(node){ 3498 if(!node) return ''; 3499 if(node.nodeType === 3){ return node.nodeValue || ''; } 3500 if(node.nodeType !== 1) return ''; 3501 var tag = String(node.tagName || '').toLowerCase(); 3502 if(['script','style','meta','link','iframe','object','embed','svg','canvas','form','input','button','textarea','select','option'].indexOf(tag) !== -1) return ''; 3503 if(tag === 'br') return '\n'; 3504 if(tag === 'hr') return '\n[hr]\n'; 3505 if(tag === 'img'){ 3506 var src = allowedUrl(node.getAttribute('src') || ''); 3507 return src ? ('\n[img]' + src + '[/img]\n') : ''; 3508 } 3509 if(tag === 'a'){ 3510 var href = allowedUrl(node.getAttribute('href') || ''); 3511 var label = childrenToMarkup(node).trim() || href; 3512 return href ? ('[url=' + href + ']' + label + '[/url]') : label; 3513 } 3514 if(tag === 'strong' || tag === 'b') return '[b]' + childrenToMarkup(node).trim() + '[/b]'; 3515 if(tag === 'em' || tag === 'i') return '[i]' + childrenToMarkup(node).trim() + '[/i]'; 3516 if(tag === 'u') return '[u]' + childrenToMarkup(node).trim() + '[/u]'; 3517 if(tag === 's' || tag === 'del' || tag === 'strike') return '[s]' + childrenToMarkup(node).trim() + '[/s]'; 3518 if(tag === 'blockquote') return '\n[quote]\n' + childrenToMarkup(node).trim() + '\n[/quote]\n'; 3519 if(tag === 'pre') return '\n[code]\n' + textOf(node).replace(/^\n+|\n+$/g, '') + '\n[/code]\n'; 3520 if(tag === 'code') return '[code]' + textOf(node).replace(/^\n+|\n+$/g, '') + '[/code]'; 3521 if(tag === 'h1') return '\n[h1]' + childrenToMarkup(node).trim() + '[/h1]\n'; 3522 if(tag === 'h2') return '\n[h2]' + childrenToMarkup(node).trim() + '[/h2]\n'; 3523 if(tag === 'h3' || tag === 'h4' || tag === 'h5' || tag === 'h6') return '\n[h3]' + childrenToMarkup(node).trim() + '[/h3]\n'; 3524 if(tag === 'ul') return listToMarkup(node, false); 3525 if(tag === 'ol') return listToMarkup(node, true); 3526 if(tag === 'table') return tableToMarkup(node); 3527 if(['p','div','section','article','header','footer','main','aside'].indexOf(tag) !== -1){ 3528 var block = childrenToMarkup(node).trim(); 3529 return block ? ('\n' + block + '\n') : '\n'; 3530 } 3531 if(tag === 'li') return '- ' + childrenToMarkup(node).trim() + '\n'; 3532 return childrenToMarkup(node); 3533 } 3534 function htmlToMarkup(html){ 3535 html = String(html || '').trim(); 3536 if(!html) return ''; 3537 var doc; 3538 try { doc = new DOMParser().parseFromString(html, 'text/html'); } catch(e){ return ''; } 3539 var root = doc && doc.body ? doc.body : null; 3540 if(!root) return ''; 3541 var out = childrenToMarkup(root); 3542 out = cleanSpace(out) 3543 .replace(/\n{4,}/g, '\n\n\n') 3544 .replace(/\[b\]\s*\[\/b\]/gi, '') 3545 .replace(/\[i\]\s*\[\/i\]/gi, '') 3546 .replace(/\[u\]\s*\[\/u\]/gi, '') 3547 .replace(/\n{3,}/g, '\n\n') 3548 .trim(); 3549 return out; 3550 } 3551 function insertAtCursor(textarea, text, replaceAll){ 3552 if(!textarea || !text) return; 3553 textarea.focus(); 3554 var val = textarea.value || ''; 3555 if(replaceAll){ 3556 textarea.value = text; 3557 textarea.setSelectionRange(text.length, text.length); 3558 } else { 3559 var start = textarea.selectionStart || 0; 3560 var end = textarea.selectionEnd || 0; 3561 var before = val.slice(0, start); 3562 var after = val.slice(end); 3563 var glueBefore = before && !/\n\n$/.test(before) ? (before.slice(-1) === '\n' ? '\n' : '\n\n') : ''; 3564 var glueAfter = after && !/^\n\n/.test(after) ? (after.charAt(0) === '\n' ? '\n' : '\n\n') : '';
3565 var insert = glueBefore + text + glueAfter; 3566 textarea.value = before + insert + after; 3567 var pos = before.length + insert.length; 3568 textarea.setSelectionRange(pos, pos); 3569 } 3570 textarea.dispatchEvent(new Event('input', {bubbles:true})); 3571 } 3572 function sanitizePreview(html){ 3573 html = String(html || ''); 3574 var doc; 3575 try { doc = new DOMParser().parseFromString(html, 'text/html'); } catch(e){ return ''; } 3576 if(!doc || !doc.body) return ''; 3577 qsa('script,style,meta,link,iframe,object,embed,svg,canvas,form,input,button,textarea,select,option', doc.body).forEach(function(n){ n.remove(); }); 3578 qsa('*', doc.body).forEach(function(el){ 3579 Array.prototype.slice.call(el.attributes || []).forEach(function(attr){ 3580 var name = attr.name.toLowerCase(); 3581 var value = attr.value || ''; 3582 if(name.indexOf('on') === 0 || name === 'style' || name === 'class' || name === 'id') el.removeAttribute(attr.name); 3583 if((name === 'href' || name === 'src') && !allowedUrl(value)) el.removeAttribute(attr.name); 3584 if(name === 'href') { el.setAttribute('target','_blank'); el.setAttribute('rel','nofollow noopener noreferrer'); } 3585 }); 3586 }); 3587 return doc.body.innerHTML; 3588 } 3589 function ensureModal(){ 3590 var modal = qs('[data-blog-html-modal]'); 3591 if(modal) return modal; 3592 modal = document.createElement('div'); 3593 modal.className = 'blog-html-modal-v239'; 3594 modal.setAttribute('data-blog-html-modal','1'); 3595 modal.hidden = true; 3596 modal.innerHTML = ''+ 3597 '<div class="blog-html-backdrop-v239" data-blog-html-close></div>'+ 3598 '<section class="blog-html-window-v239" role="dialog" aria-modal="true" aria-labelledby="blogHtmlTitle">'+ 3599 '<div class="blog-html-head-v239"><div><span class="eyebrow">HTML İçerik</span><h2 id="blogHtmlTitle">HTML yapıÅtır / içeriÄe aktar</h2><p class="muted">Yapay zekadan veya baÅka sayfadan aldıÄınız biçimli HTML; baÅlık, liste, baÄlantı, görsel, alıntı ve kod yapısına güvenli Åekilde çevrilir.</p></div><button type="button" class="blog-html-close-v239" data-blog-html-close aria-label="Kapat">
3599Ã</button></div>'+ 3600 '<div class="blog-html-body-v239">'+ 3601 '<div class="blog-html-pane-v239"><label>HTML kaynak<textarea class="blog-html-source-v239" data-blog-html-source spellcheck="false" placeholder="HTML içeriÄi buraya yapıÅtırın..."></textarea></label></div>'+ 3602 '<div class="blog-html-pane-v239"><strong>Ãnizleme</strong><div class="blog-html-preview-v239" data-blog-html-preview><p class="muted">HTML yapıÅtırdıÄınızda güvenli önizleme burada görünür.</p></div></div>'+ 3603 '</div>'+ 3604 '<div class="blog-html-actions-v239"><div class="blog-html-actions-left-v239"><span class="blog-html-status-v239" data-blog-html-status>Hazır.</span></div><div class="blog-html-actions-right-v239"><button type="button" class="btn" data-blog-html-convert-replace>Tüm yazıyı deÄiÅtir</button><button type="button" class="btn primary" data-blog-html-convert-insert>İmleç yerine ekle</button><button type="button" class="btn" data-blog-html-close>Kapat</button></div></div>'+ 3605 '</section>'; 3606 body().appendChild(modal); 3607 return modal; 3608 } 3609 function activeTextarea(){ return window.__blogHtmlActiveTextarea || qs('.blog-pro-editor-form textarea[name="body"], [data-blog-seo-body]'); } 3610 function setStatus(modal, msg, err){ 3611 var out = qs('[data-blog-html-status]', modal); 3612 if(out){ out.textContent = msg || ''; out.style.color = err ? '#dc2626' : ''; } 3613 } 3614 function openModal(textarea){ 3615 window.__blogHtmlActiveTextarea = textarea || activeTextarea(); 3616 var modal = ensureModal(); 3617 modal.hidden = false; 3618 modal.setAttribute('aria-hidden','false'); 3619 body().classList.add('blog-html-modal-open-v239'); 3620 var src = qs('[data-blog-html-source]', modal); 3621 var prev = qs('[data-blog-html-preview]', modal); 3622 if(src && !src.value){ src.value = ''; } 3623 if(prev){ prev.innerHTML = '<p class="muted">HTML yapıÅtırdıÄınızda güvenli önizleme burada görünür.</p>'; } 3624 setStatus(modal, 'HTML içeriÄi yapıÅtırıp ekleyebilirsiniz.', false); 3625 setTimeout(function(){ if(src) src.focus(); }, 40); 3626 } 3627 function closeModal(){ 3628 var modal = qs('[data-blog-html-modal]'); 3629 if(!modal) return; 3630 modal.hidden = true; 3631 modal.setAttribute('aria-hidden','true'); 3632 body().classList.remove('blog-html-modal-open-v239'); 3633 } 3634 function updatePreview(){ 3635 var modal = ensureModal(); 3636 var src = qs('[data-blog-html-source]', modal); 3637 var prev = qs('[data-blog-html-preview]', modal); 3638 if(!src || !prev) return; 3639 var html = src.value || ''; 3640 prev.innerHTML = html.trim() ? sanitizePreview(html) : '<p class="muted">HTML yapıÅtırdıÄınızda güvenli önizleme burada görünür.</p>'; 3641 var converted = htmlToMarkup(html); 3642 setStatus(modal, converted ? ('DönüÅtürülecek içerik hazır: ' + converted.length + ' karakter.') : 'DönüÅtürülebilecek HTML bulunamadı.', !converted && !!html.trim()); 3643 } 3644 function convert(replaceAll){ 3645 var modal = ensureModal(); 3646 var src = qs('[data-blog-html-source]', modal); 3647 var ta = activeTextarea(); 3648 var converted = htmlToMarkup(src ? src.value : ''); 3649 if(!converted){ setStatus(modal, 'DönüÅtürülebilecek HTML bulunamadı.', true); return; } 3650 insertAtCursor(ta, converted, replaceAll); 3651 setStatus(modal, replaceAll ? 'HTML dönüÅtürüldü ve yazı alanının tamamı güncellendi.' : 'HTML dönüÅtürüldü ve imleç yerine eklendi.', false); 3652 setTimeout(closeModal, 260); 3653 } 3654 function addButton(editor){ 3655 if(!editor || editor.querySelector('[data-blog-html-open]')) return; 3656 var toolbar = qs('.ffp-editor-toolbar', editor); 3657 if(!toolbar) return; 3658 var btn = document.createElement('button'); 3659 btn.type = 'button'; 3660 btn.setAttribute('data-blog-html-open','1'); 3661 btn.title = 'HTML yapıÅtır / dönüÅtür'; 3662 btn.setAttribute('aria-label','HTML yapıÅtır / dönüÅtür'); 3663 btn.innerHTML = '</> HTML'; 3664 var imageBtn = toolbar.querySelector('[data-editor-image-open]'); 3665 toolbar.insertBefore(btn, imageBtn || null); 3666 var editorFoot = qs('.ffp-editor-foot', editor); 3667 if(editorFoot && !qs('.blog-editor-paste-note-v239', editor)){ 3668 var note = document.createElement('small'); 3669 note.className = 'blog-editor-paste-note-v239'; 3670 note.textContent = 'Biçimli HTML kopyalarsanız editör baÅlık, liste, baÄlantı, görsel ve kod yapısını koruyarak dönüÅtürür.'; 3671 editorFoot.appendChild(note); 3672 } 3673 }
3674 function init(){ 3675 qsa('.blog-pro-editor-form [data-ffp-editor], .blog-editor-pro-v226 [data-ffp-editor]').forEach(addButton); 3676 } 3677 document.addEventListener('DOMContentLoaded', init); 3678 if(document.readyState !== 'loading') init(); 3679 document.addEventListener('click', function(e){ 3680 var open = e.target.closest('[data-blog-html-open]'); 3681 if(open){ e.preventDefault(); var ed = open.closest('[data-ffp-editor]'); openModal(ed ? qs('textarea', ed) : null); return; } 3682 if(e.target.closest('[data-blog-html-close]')){ e.preventDefault(); closeModal(); return; } 3683 if(e.target.closest('[data-blog-html-convert-insert]')){ e.preventDefault(); convert(false); return; } 3684 if(e.target.closest('[data-blog-html-convert-replace]')){ e.preventDefault(); convert(true); return; } 3685 }); 3686 document.addEventListener('input', function(e){ if(e.target.closest('[data-blog-html-source]')) updatePreview(); }); 3687 document.addEventListener('paste', function(e){ 3688 var ta = e.target.closest ? e.target.closest('.blog-pro-editor-form textarea[name="body"], [data-blog-seo-body]') : null; 3689 if(!ta || !e.clipboardData) return; 3690 var html = e.clipboardData.getData('text/html'); 3691 if(!html || !html.trim()) return; 3692 var converted = htmlToMarkup(html); 3693 if(!converted) return; 3694 e.preventDefault(); 3695 insertAtCursor(ta, converted, false); 3696 }); 3697 document.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeModal(); }); 3698})(); 3699 3700/* Blog tüm içerikler sayfasında 404'süz sonsuz yükleme */ 3701(function(){ 3702 function ready(fn){ if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); } 3703 function encodeQuery(params){ 3704 var parts = []; 3705 Object.keys(params || {}).forEach(function(key){ 3706 var value = params[key]; 3707 if(value === null || value === undefined || value === '') return; 3708 parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(String(value))); 3709 }); 3710 return parts.join('&'); 3711 } 3712 function addParams(url, params){ 3713 var qs = encodeQuery(params); 3714 if(!qs) return url; 3715 return url + (url.indexOf('?') === -1 ? '?' : '&') + qs; 3716 } 3717 ready(function(){ 3718 var grid = document.querySelector('[data-blog-infinite-v262]'); 3719 if(!grid || grid.getAttribute('data-blog-infinite-ready-v263') === '1') return; 3720 grid.setAttribute('data-blog-infinite-ready-v263', '1'); 3721 var status = document.querySelector('[data-blog-load-status-v262]'); 3722 var loading = false; 3723 var hasMore = grid.getAttribute('data-has-more') === '1'; 3724 var nextPage = parseInt(grid.getAttribute('data-next-page') || '2', 10) || 2; 3725 var limit = parseInt(grid.getAttribute('data-limit') || '12', 10) || 12; 3726 var baseUrl = grid.getAttribute('data-url') || ''; 3727 var category = grid.getAttribute('data-category') || ''; 3728 var q = grid.getAttribute('data-q') || ''; 3729 function setStatus(text, isError){ 3730 if(!status) return; 3731 status.innerHTML = '<span' + (isError ? ' class="is-error"' : '') + '>
3731' + text + '</span>'; 3732 } 3733 function loadNext(){ 3734 if(loading || !hasMore || !baseUrl) return; 3735 loading = true; 3736 setStatus('İçerikler yükleniyor...', false); 3737 var url = addParams(baseUrl, {page: nextPage, limit: limit, category: category, q: q}); 3738 fetch(url, {headers:{'X-Requested-With':'XMLHttpRequest'}, credentials:'same-origin'}) 3739 .then(function(res){ if(!res.ok) throw new Error('HTTP ' + res.status); return res.json(); }) 3740 .then(function(data){ 3741 if(!data || !data.ok) throw new Error((data && data.message) || 'İçerikler yüklenemedi.'); 3742 if(data.html){ grid.insertAdjacentHTML('beforeend', data.html); } 3743 hasMore = !!data.has_more; 3744 nextPage = parseInt(data.next_page || (nextPage + 1), 10) || (nextPage + 1); 3745 grid.setAttribute('data-has-more', hasMore ? '1' : '0'); 3746 grid.setAttribute('data-next-page', String(nextPage)); 3747 setStatus(hasMore ? 'Daha fazla içerik için aÅaÄı kaydırın.' : 'Tüm içerikler listelendi.', false); 3748 }) 3749 .catch(function(){ 3750 hasMore = false; 3751 grid.setAttribute('data-has-more', '0'); 3752 setStatus('İçerikler yüklenirken sorun oluÅtu. Sayfayı yenileyip tekrar deneyin.', true); 3753 }) 3754 .finally(function(){ loading = false; }); 3755 } 3756 if(!hasMore){ setStatus('Tüm içerikler listelendi.', false); return; } 3757 setStatus('Daha fazla içerik için aÅaÄı kaydırın.', false); 3758 if('IntersectionObserver' in window && status){ 3759 var observer = new IntersectionObserver(function(entries){ 3760 entries.forEach(function(entry){ if(entry.isIntersecting) loadNext(); }); 3761 }, {rootMargin:'320px 0px'}); 3762 observer.observe(status); 3763 } else { 3764 window.addEventListener('scroll', function(){ 3765 if(!hasMore || loading) return; 3766 var nearBottom = (window.innerHeight + window.scrollY) >= (document.documentElement.scrollHeight - 420); 3767 if(nearBottom) loadNext(); 3768 }, {passive:true}); 3769 } 3770 }); 3771})(); 3772 3773 3774/* Araçlar menüsü masaüstünde sadece tıklama ile açılır/kapanır; hover/focus kendi kendine açamaz */ 3775(function(){ 3776 'use strict'; 3777 function ready(fn){ if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); } 3778 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 3779 function closeToolsMenu(exceptWrap){ 3780 qsa('.tools-top-dropdown.is-open, .top-menu-dropdown.is-open').forEach(function(wrap){ 3781 if(exceptWrap && wrap === exceptWrap) return; 3782 wrap.classList.remove('is-open'); 3783 var b = wrap.querySelector('[data-tools-menu-toggle]'); 3784 if(b){ b.setAttribute('aria-expanded','false'); } 3785 }); 3786 } 3787 ready(function(){ 3788 qsa('[data-tools-menu-toggle]').forEach(function(btn){ 3789 var wrap = btn.closest('.tools-top-dropdown') || btn.closest('.top-menu-dropdown'); 3790 if(!wrap || btn.dataset.toolsMenuBound === '1') return; 3791 btn.dataset.toolsMenuBound = '1'; 3792 wrap.classList.remove('is-open'); 3793 btn.setAttribute('aria-expanded','false'); 3794 btn.addEventListener('click', function(e){ 3795 e.preventDefault(); 3796 e.stopPropagation(); 3797 e.stopImmediatePropagation(); 3798 var willOpen = !wrap.classList.contains('is-open'); 3799 closeToolsMenu(wrap); 3800 wrap.classList.toggle('is-open', willOpen); 3801 btn.setAttribute('aria-expanded', willOpen ? 'true' : 'false'); 3802 if(!willOpen && document.activeElement === btn){ 3803 try { btn.blur(); } catch(err) {} 3804 } 3805 }, true); 3806 wrap.addEventListener('click', function(e){ e.stopPropagation(); }); 3807 }); 3808 document.addEventListener('click', function(e){ 3809 var target = e.target; 3810 if(target && target.closest && target.closest('[data-tools-menu-toggle], .tools-top-dropdown, .top-menu-dropdown.tools-top-dropdown')){ 3811 return; 3812 } 3813 closeToolsMenu(); 3814 }, false); 3815 document.addEventListener('keydown', function(e){ 3816 if(e.key === 'Escape'){ closeToolsMenu(); } 3817 });
3818 qsa('[data-mobile-tools-toggle]').forEach(function(btn){ 3819 var submenu = btn.nextElementSibling; 3820 if(!submenu || !submenu.classList.contains('mobile-tools-submenu') || btn.dataset.mobileToolsBound === '1') return; 3821 btn.dataset.mobileToolsBound = '1'; 3822 submenu.hidden = true; 3823 btn.setAttribute('aria-expanded','false'); 3824 btn.addEventListener('click', function(e){ 3825 e.preventDefault(); 3826 e.stopPropagation(); 3827 var open = submenu.hidden; 3828 submenu.hidden = !open; 3829 btn.classList.toggle('is-open', open); 3830 btn.setAttribute('aria-expanded', open ? 'true' : 'false'); 3831 if(open){ 3832 var scrollPane = btn.closest('[data-mobile-nav-links]'); 3833 if(scrollPane){ 3834 requestAnimationFrame(function(){ 3835 var top = btn.offsetTop - 8; 3836 if(top < scrollPane.scrollTop) scrollPane.scrollTo({top:Math.max(0, top), behavior:'smooth'}); 3837 }); 3838 } 3839 } 3840 }); 3841 }); 3842 }); 3843})(); 3844 3845 3846/* flat baÅarı/hata onay mesajları - yeÅil baÅarı otomatik kapanır, hatalar kırmızı görünür */ 3847(function(){ 3848 'use strict'; 3849 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 3850 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 3851 function normalizeType(type){ 3852 type = String(type || '').toLowerCase().trim(); 3853 if(['ok','done','saved','green','success'].indexOf(type) !== -1) return 'success'; 3854 if(['error','err','failed','fail','invalid','no','red','danger'].indexOf(type) !== -1) return 'danger'; 3855 if(['warn','warning','pending'].indexOf(type) !== -1) return 'warning'; 3856 if(['info','notice','blue'].indexOf(type) !== -1) return 'info'; 3857 return 'info'; 3858 } 3859 function iconFor(type){ 3860 if(type === 'success') return 'â'; 3861 if(type === 'danger') return '!'; 3862 if(type === 'warning') return '!'; 3863 return 'i'; 3864 } 3865 function dismissAlert(item){ 3866 if(!item || item.dataset.dismissed === '1') return; 3867 item.dataset.dismissed = '1'; 3868 item.classList.add('is-hiding'); 3869 window.setTimeout(function(){ if(item && item.parentNode) item.parentNode.removeChild(item); }, 260); 3870 } 3871 function prepareAlert(item){ 3872 if(!item || item.dataset.topicMobileReady === '1') return; 3873 item.dataset.topicMobileReady = '1'; 3874 var type = normalizeType(item.getAttribute('data-alert-type') || (item.classList.contains('success') ? 'success' : item.classList.contains('danger') ? 'danger' : item.classList.contains('warning') ? 'warning' : item.classList.contains('info') ? 'info' : '')); 3875 item.classList.remove('error','failed','invalid','ok','done','saved','green','red'); 3876 item.classList.add(type); 3877 item.setAttribute('data-alert-type', type); 3878 var msg = item.querySelector('.global-alert-message') || item.querySelector('span:not(.global-alert-icon)'); 3879 if(!item.querySelector('.global-alert-icon')){ 3880 var ic = document.createElement('span'); 3881 ic.className = 'global-alert-icon'; 3882 ic.setAttribute('aria-hidden','true'); 3883 ic.textContent = iconFor(type); 3884 item.insertBefore(ic, item.firstChild); 3885 } else { 3886 item.querySelector('.global-alert-icon').textContent = iconFor(type); 3887 } 3888 if(msg && !msg.classList.contains('global-alert-message')) msg.classList.add('global-alert-message'); 3889 if(!item.querySelector('[data-global-alert-close]')){ 3890 var btn = document.createElement('button'); 3891 btn.type = 'button'; 3892 btn.setAttribute('data-global-alert-close',''); 3893 btn.setAttribute('aria-label','Kapat'); 3894 btn.textContent = 'Ã'; 3895 item.appendChild(btn); 3896 } 3897 var shouldAutoClose = item.getAttribute('data-auto-close') === '1' || type === 'success'; 3898 if(shouldAutoClose){ 3899 var delay = parseInt(item.getAttribute('data-auto-close-delay') || '4200', 10); 3900 if(!delay || delay < 1800) delay = 4200; 3901 window.setTimeout(function(){ dismissAlert(item); }, delay); 3902 } 3903 } 3904 function prepareAll(){ 3905 qsa('.global-alert-item,.alert.success,.alert.danger,.alert.warning,.alert.info').forEach(prepareAlert); 3906 } 3907 window.WMTFlash = window.WMTFlash || {}; 3908 window.WMTFlash.normalizeType = normalizeType; 3909 window.WMTFlash.prepareAll = prepareAll;
3910 window.WMTFlash.dismiss = dismissAlert; 3911 window.WMTFlash.show = function(type, message, opts){ 3912 opts = opts || {}; 3913 type = normalizeType(type); 3914 message = String(message || (type === 'success' ? 'İÅlem baÅarıyla tamamlandı.' : 'İÅlem tamamlanamadı.')); 3915 var stack = qs('[data-global-alert-stack]'); 3916 if(!stack){ 3917 stack = document.createElement('div'); 3918 stack.className = 'global-alert-stack'; 3919 stack.setAttribute('data-global-alert-stack','1'); 3920 stack.setAttribute('aria-live','polite'); 3921 stack.setAttribute('aria-atomic','true'); 3922 document.body.appendChild(stack); 3923 } 3924 var item = document.createElement('div'); 3925 item.className = 'alert ' + type + ' global-alert-item'; 3926 item.setAttribute('data-global-alert-item',''); 3927 item.setAttribute('data-alert-type', type); 3928 item.setAttribute('data-auto-close', (opts.autoClose || type === 'success') ? '1' : '0'); 3929 item.innerHTML = '<span class="global-alert-icon" aria-hidden="true">' + iconFor(type) + '</span><span class="global-alert-message"></span><button type="button" data-global-alert-close aria-label="Kapat">
3929Ã</button>'; 3930 item.querySelector('.global-alert-message').textContent = message; 3931 stack.appendChild(item); 3932 prepareAlert(item); 3933 return item; 3934 }; 3935 document.addEventListener('click', function(e){ 3936 var btn = e.target && e.target.closest ? e.target.closest('[data-global-alert-close]') : null; 3937 if(!btn) return; 3938 var item = btn.closest('.global-alert-item,.alert'); 3939 if(item) dismissAlert(item); 3940 }); 3941 document.addEventListener('DOMContentLoaded', prepareAll); 3942 if(document.readyState !== 'loading') prepareAll(); 3943})(); 3944 3945/* Hesaplama sayfası seçimli/sade çalıÅma modu */ 3946(function(){ 3947 'use strict'; 3948 function qs(sel, ctx){ return (ctx || document).querySelector(sel); } 3949 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); } 3950 function initCalculatorSelector(){ 3951 qsa('[data-calculator-suite]').forEach(function(suite){ 3952 if(suite.dataset.calcSelectorReady === '1') return; 3953 suite.dataset.calcSelectorReady = '1'; 3954 var panel = qs('[data-calculator-selector]'); 3955 var select = qs('[data-calculator-select]', panel || document); 3956 var forms = qsa('.calculator-card-mini', suite); 3957 var buttons = qsa('[data-calc-open]', panel || document); 3958 3959 forms.forEach(function(form){ 3960 var input = qs('input[name="calc_type"]', form); 3961 var type = input ? input.value : ''; 3962 form.setAttribute('data-calc-panel', type); 3963 form.setAttribute('aria-hidden', 'true'); 3964 var submit = qs('button[type="submit"]', form); 3965 if(submit && !qs('.calculator-panel-actions', form)){ 3966 var actions = document.createElement('div'); 3967 actions.className = 'calculator-panel-actions'; 3968 submit.parentNode.insertBefore(actions, submit); 3969 actions.appendChild(submit); 3970 var back = document.createElement('button'); 3971 back.type = 'button'; 3972 back.className = 'calculator-back-btn'; 3973 back.setAttribute('data-calc-close','1'); 3974 back.textContent = 'Seçime dön'; 3975 actions.appendChild(back); 3976 } 3977 }); 3978 3979 function setActiveVisual(type){ 3980 buttons.forEach(function(btn){ btn.classList.toggle('is-active', btn.getAttribute('data-calc-open') === type); }); 3981 if(select && select.value !== type) select.value = type || ''; 3982 } 3983 function openCalc(type, shouldScroll){ 3984 type = String(type || '').trim(); 3985 var has = false; 3986 forms.forEach(function(form){ 3987 var ok = form.getAttribute('data-calc-panel') === type; 3988 form.classList.toggle('is-active', ok); 3989 form.setAttribute('aria-hidden', ok ? 'false' : 'true'); 3990 if(ok) has = true; 3991 }); 3992 suite.classList.toggle('has-active', has); 3993 setActiveVisual(has ? type : ''); 3994 if(has && shouldScroll){ 3995 window.setTimeout(function(){ suite.scrollIntoView({behavior:'smooth', block:'start'}); }, 30); 3996 } 3997 } 3998 function closeCalc(){ 3999 forms.forEach(function(form){ form.classList.remove('is-active'); form.setAttribute('aria-hidden','true'); }); 4000 suite.classList.remove('has-active'); 4001 setActiveVisual(''); 4002 if(panel) panel.scrollIntoView({behavior:'smooth', block:'start'}); 4003 } 4004 4005 if(select){ 4006 select.addEventListener('change', function(){ 4007 if(this.value) openCalc(this.value, true); 4008 else closeCalc(); 4009 }); 4010 } 4011 buttons.forEach(function(btn){ 4012 btn.addEventListener('click', function(){ openCalc(btn.getAttribute('data-calc-open'), true); }); 4013 }); 4014 suite.addEventListener('click', function(e){ 4015 var btn = e.target && e.target.closest ? e.target.closest('[data-calc-close]') : null; 4016 if(!btn) return; 4017 e.preventDefault(); 4018 closeCalc(); 4019 }); 4020 4021 var initial = suite.getAttribute('data-active-calc') || ''; 4022 if(!initial && window.location.hash && window.location.hash.indexOf('#calc-') === 0){ initial = window.location.hash.replace('#calc-',''); } 4023 if(initial) openCalc(initial, false); 4024 else closeCalc(); 4025 }); 4026 } 4027 document.addEventListener('DOMContentLoaded', initCalculatorSelector); 4028 if(document.readyState !== 'loading') initCalculatorSelector(); 4029})(); 4030
4031/* Genel yazı editörü HTML yapıÅtırma ve anlık düzgün dönüÅtürme */ 4032(function(){ 4033 function qs(sel, ctx){ return (ctx||document).querySelector(sel); } 4034 function qsa(sel, ctx){ return Array.prototype.slice.call((ctx||document).querySelectorAll(sel)); } 4035 function allowedUrl(url){ 4036 url=String(url||'').trim(); 4037 if(!url) return ''; 4038 if(url.charAt(0)==='/') return url; 4039 if(/^https?:\/\//i.test(url)) return url; 4040 return ''; 4041 } 4042 function textOf(node){ return (node && (node.textContent || '')) || ''; } 4043 function clean(text){ 4044 return String(text||'') 4045 .replace(/\r/g,'') 4046 .replace(/[ \t]+\n/g,'\n') 4047 .replace(/\n[ \t]+/g,'\n') 4048 .replace(/\n{4,}/g,'\n\n\n') 4049 .trim(); 4050 } 4051 function children(node){ return qsa(':scope > *', node).length ? Array.prototype.slice.call(node.childNodes).map(toMarkup).join('') : textOf(node); } 4052 function list(node, ordered){ 4053 var i=1, rows=[]; 4054 qsa(':scope > li', node).forEach(function(li){ 4055 var line=children(li).replace(/\n+/g,' ').trim(); 4056 if(line) rows.push((ordered ? (i++) + '. ' : '- ') + line); 4057 }); 4058 return rows.length ? '\n' + rows.join('\n') + '\n' : ''; 4059 } 4060 function table(node){ 4061 var rows=[]; 4062 qsa('tr', node).forEach(function(tr){ 4063 var cells=[]; 4064 qsa('th,td', tr).forEach(function(td){ cells.push(textOf(td).replace(/\s+/g,' ').trim()); }); 4065 if(cells.length) rows.push('| ' + cells.join(' | ') + ' |'); 4066 }); 4067 return rows.length ? '\n[code]\n' + rows.join('\n') + '\n[/code]\n' : ''; 4068 } 4069 function toMarkup(node){ 4070 if(!node) return ''; 4071 if(node.nodeType===3) return node.nodeValue || ''; 4072 if(node.nodeType!==1) return ''; 4073 var tag=String(node.tagName||'').toLowerCase(); 4074 if(['script','style','meta','link','iframe','object','embed','svg','canvas','form','input','button','textarea','select','option'].indexOf(tag)!==-1) return ''; 4075 if(tag==='br') return '\n'; 4076 if(tag==='hr') return '\n[hr]\n'; 4077 if(tag==='img'){ 4078 var src=allowedUrl(node.getAttribute('src')||''); 4079 return src ? '\n[img]'+src+'[/img]\n' : ''; 4080 } 4081 if(tag==='a'){ 4082 var href=allowedUrl(node.getAttribute('href')||''); 4083 var label=clean(children(node)) || href; 4084 return href ? '[url='+href+']'+label+'[/url]' : label; 4085 } 4086 if(tag==='strong'||tag==='b') return '[b]'+clean(children(node))+'[/b]'; 4087 if(tag==='em'||tag==='i') return '[i]'+clean(children(node))+'[/i]'; 4088 if(tag==='u') return '[u]'+clean(children(node))+'[/u]'; 4089 if(tag==='s'||tag==='del'||tag==='strike') return '[s]'+clean(children(node))+'[/s]'; 4090 if(tag==='blockquote') return '\n[quote]\n'+clean(children(node))+'\n[/quote]\n'; 4091 if(tag==='pre') return '\n[code]\n'+String(textOf(node)).replace(/^\n+|\n+$/g,'')+'\n[/code]\n'; 4092 if(tag==='code') return '[code]'+String(textOf(node)).replace(/^\n+|\n+$/g,'')+'[/code]'; 4093 if(tag==='h1') return '\n[h1]'+clean(children(node))+'[/h1]\n'; 4094 if(tag==='h2') return '\n[h2]'+clean(children(node))+'[/h2]\n'; 4095 if(/^h[3-6]$/.test(tag)) return '\n[h3]'+clean(children(node))+'[/h3]\n'; 4096 if(tag==='ul') return list(node,false); 4097 if(tag==='ol') return list(node,true); 4098 if(tag==='table') return table(node); 4099 if(tag==='li') return '- '+clean(children(node))+'\n'; 4100 if(['p','div','section','article','header','footer','main','aside'].indexOf(tag)!==-1){ 4101 var block=clean(children(node)); 4102 return block ? '\n'+block+'\n' : '\n'; 4103 } 4104 return children(node); 4105 } 4106 function htmlToMarkup(html){ 4107 html=String(html||'').trim(); if(!html) return ''; 4108 var doc; try{ doc=new DOMParser().parseFromString(html,'text/html'); }catch(e){ return ''; } 4109 if(!doc || !doc.body) return ''; 4110 return clean(Array.prototype.slice.call(doc.body.childNodes).map(toMarkup).join('')) 4111 .replace(/\[b\]\s*\[\/b\]/gi,'') 4112 .replace(/\[i\]\s*\[\/i\]/gi,'') 4113 .replace(/\[u\]\s*\[\/u\]/gi,'') 4114 .replace(/\n{3,}/g,'\n\n') 4115 .trim(); 4116 } 4117 function insert(textarea, text){ 4118 if(!textarea || !text) return; 4119 var val=textarea.value||'', start=textarea.selectionStart||0, end=textarea.selectionEnd||0; 4120 var before=val.slice(0,start), after=val.slice(end); 4121 var glueBefore=before && !/\n\n$/.test(before) ? (before.slice(-1)==='\n'?'\n':'\n\n') : ''; 4122 var glueAfter=after && !/^\n\n/.test(after) ? (after.charAt(0)==='\n'?'\n':'\n\n') : ''; 4123 var add=glueBefore+text+glueAfter; 4124 textarea.value=before+add+after; 4125 var pos=before.length+add.length; 4126 textarea.setSelectionRange(pos,pos); 4127 textarea.dispatchEvent(new Event('input',{bubbles:true})); 4128 } 4129 function showStatus(textarea){ 4130 var editor=textarea.closest('[data-ffp-editor]'); if(!editor) return; 4131 var foot=qs('.ffp-editor-foot', editor); if(!foot) return; 4132 var old=qs('.ffp-editor-paste-status-v290', foot); if(old) old.remove();
4133 var badge=document.createElement('span'); 4134 badge.className='ffp-editor-paste-status-v290'; 4135 badge.textContent='HTML biçimi dönüÅtürüldü'; 4136 foot.appendChild(badge); 4137 setTimeout(function(){ if(badge && badge.parentNode) badge.remove(); }, 2800); 4138 } 4139 document.addEventListener('paste', function(e){ 4140 if(e.defaultPrevented || !e.clipboardData) return; 4141 var target=e.target && e.target.closest ? e.target.closest('[data-ffp-editor] textarea') : null; 4142 if(!target) return; 4143 var html=e.clipboardData.getData('text/html'); 4144 if(!html || !html.trim()) return; 4145 var converted=htmlToMarkup(html); 4146 if(!converted) return; 4147 e.preventDefault(); 4148 insert(target, converted); 4149 showStatus(target); 4150 }, true); 4151})(); 4152 4153/* Grup bazlı özel mesaj kotaları, canlı teslim/okundu tikleri ve yenilemesiz iÅlemler */ 4154(function(){ 4155 function qs(sel, root){ return (root || document).querySelector(sel); } 4156 function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); } 4157 function esc(value){ return String(value == null ? '' : value).replace(/[&<>"']/g, function(ch){ return ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]); }); } 4158 function br(value){ return esc(value).replace(/\n/g, '<br>'); } 4159 function csrf(root){ var input=qs('input[name="_csrf"]', root || document); return input ? input.value : ((document.body && document.body.getAttribute('data-csrf-token')) || ''); } 4160 function initial(name){ var text=String(name || '').trim(); return esc(text ? text.charAt(0).toUpperCase() : '?'); } 4161 4162 function setup(root){ 4163 if(!root || root.getAttribute('data-pm-ready') === '1') return; 4164 root.setAttribute('data-pm-ready','1'); 4165 var liveUrl=root.getAttribute('data-pm-live-url') || ''; 4166 var deleteUrl=root.getAttribute('data-pm-delete-url') || ''; 4167 var unblockUrl=root.getAttribute('data-pm-unblock-url') || ''; 4168 var compose=qs('[data-pm-compose-form]', root); 4169 var toInput=qs('[data-pm-to]', root); 4170 var subjectInput=qs('[data-pm-subject]', root); 4171 var bodyInput=qs('[data-pm-body]', root); 4172 var polling=false, timer=0, targetTimer=0, alertTimer=0; 4173 function currentPage(type){ var value=parseInt(root.getAttribute('data-pm-'+type+'-page')||'1',10); return value>0?value:1; } 4174 function appendPages(fd){ fd.set('inbox_page',String(currentPage('inbox'))); fd.set('sent_page',String(currentPage('sent'))); return fd; } 4175 4176 function showAlert(message, ok){ 4177 var box=qs('[data-pm-alert]', root); if(!box) return; 4178 box.hidden=false; box.className='pm-live-alert '+(ok?'is-success':'is-error'); box.textContent=String(message || (ok?'İÅlem tamamlandı.':'İÅlem tamamlanamadı.')); 4179 window.clearTimeout(alertTimer); alertTimer=window.setTimeout(function(){ box.hidden=true; }, 4200); 4180 } 4181 function request(url, options){ 4182 options=options || {}; 4183 options.credentials='same-origin'; options.cache='no-store'; 4184 options.headers=Object.assign({'Accept':'application/json','X-Requested-With':'XMLHttpRequest'}, options.headers || {}); 4185 return fetch(url, options).then(function(res){ 4186 return res.text().then(function(text){ 4187 var payload=null; try{ payload=text ? JSON.parse(text) : null; }catch(e){} 4188 if(!payload) payload={ok:false,message:'Sunucu yanıtı okunamadı. Güncelleme merkezini çalıÅtırın.'}; 4189 payload.http_status=res.status; return payload; 4190 }); 4191 }); 4192 } 4193 function postForm(form){ 4194 var fd=appendPages(new FormData(form)); if(!fd.has('_csrf')) fd.set('_csrf', csrf(root)); fd.set('ajax','1'); 4195 return request(form.action, {method:'POST',body:fd}); 4196 } 4197 function deleteForm(id){ 4198 var fd=appendPages(new FormData()); fd.set('_csrf',csrf(root)); fd.set('id',String(id)); fd.set('to',toInput ? toInput.value.trim() : ''); fd.set('ajax','1'); 4199 return request(deleteUrl,{method:'POST',body:fd}); 4200 } 4201 function renderEmpty(type){ 4202 return type==='inbox' 4203 ? '<div class="pm-empty"><span>ð</span><strong>Gelen mesaj yok</strong><p class="muted">Yeni mesajlar geldiÄinde burada listelenecek.</p></div>' 4204 : '<div class="pm-empty"><span>ð¤</span><strong>GönderilmiÅ mesaj yok</strong><p class="muted">GönderdiÄiniz mesajlar burada görünecek.</p></div>'; 4205 } 4206 function actionForm(id){ 4207 return '<form method="post" action="'+esc(deleteUrl)+'" data-pm-action-form><input type="hidden" name="_csrf" value="'+esc(csrf(root))+'"><input type="hidden" name="id" value="'+esc(id)+'"><button class="btn small">ðï¸ Sil</button></form>'; 4208 } 4209 function renderMessage(m, type){ 4210 var username=String(m.username || '');
4211 var replySubject='Cevap: '+String(m.subject || ''); 4212 var isSent=type==='sent'; 4213 var status=String(m.status || 'delivered')==='read' ? 'read' : 'delivered'; 4214 var ticks=status==='read' ? 'ââ' : 'â'; 4215 var statusLabel=status==='read' ? 'Okundu' : 'Teslim edildi'; 4216 return '<article class="pm-thread '+(isSent?'sent ':'')+((!isSent && m.unread)?'unread':'')+'" data-pm-message-id="'+esc(m.id)+'">' 4217 +'<div class="pm-avatar '+(isSent?'sent':'')+'">'+(isSent?ticks:initial(username))+'</div>' 4218 +'<div class="pm-thread-main">' 4219 +'<div class="pm-thread-top"><strong>'+esc(m.subject || '')+'</strong><time>'+esc(m.created_label || m.created_at || '')+'</time></div>' 4220 +'<div class="pm-thread-meta"><span>'+(isSent?'Alıcı':'Gönderen')+'</span><b>'+esc(username)+'</b>' 4221 +(isSent?'<em class="pm-delivery-status is-'+status+'" title="'+statusLabel+'"><i>'+ticks+'</i>'+statusLabel+'</em>':(m.unread?'<em>Yeni</em>':''))+'</div>' 4222 +'<p>'+br(m.body || '')+'</p>' 4223 +'<div class="pm-item-actions pm-thread-actions">' 4224 +'<a class="btn small '+(!isSent?'primary':'')+'" href="#" data-pm-reply-to="'+esc(username)+'" data-pm-reply-subject="'+esc(replySubject)+'">'+(isSent?'âï¸ Tekrar Yaz':'â©ï¸ Cevap Yaz')+'</a>' 4225 +actionForm(m.id) 4226 +'</div></div></article>'; 4227 } 4228 function renderLists(payload){ 4229 ['inbox','sent'].forEach(function(type){ 4230 var list=qs('[data-pm-list="'+type+'"]',root); if(!list) return; 4231 var rows=Array.isArray(payload[type]) ? payload[type] : []; 4232 list.innerHTML=rows.length ? rows.map(function(m){ return renderMessage(m,type); }).join('') : renderEmpty(type); 4233 }); 4234 } 4235 function renderBlocks(rows){ 4236 var list=qs('[data-pm-block-list]',root); if(!list) return; 4237 rows=Array.isArray(rows)?rows:[]; 4238 if(!rows.length){ list.innerHTML='<p class="muted">Engellenen kullanıcı yok.</p>'; return; } 4239 list.innerHTML=rows.map(function(row){ 4240 return '<form method="post" action="'+esc(unblockUrl)+'" class="pm-block-row" data-pm-action-form><input type="hidden" name="_csrf" value="'+esc(csrf(root))+'"><input type="hidden" name="id" value="'+esc(row.id)+'"><span>'+esc(row.username)+'</span><button class="btn small">Engeli Kaldır</button></form>'; 4241 }).join(''); 4242 }
4243 function renderSummary(summary, quota){ 4244 summary=summary||{}; quota=quota||{}; 4245 ['inbox','sent','unread'].forEach(function(key){ var el=qs('[data-pm-summary="'+key+'"]',root); if(el) el.textContent=String(parseInt(summary[key]||0,10)||0); }); 4246 qsa('[data-pm-count]',root).forEach(function(el){ var key=el.getAttribute('data-pm-count'); el.textContent=String(parseInt(summary[key]||0,10)||0)+' mesaj'; }); 4247 var conv=qs('[data-pm-summary="conversation"]',root); if(conv) conv.textContent=String(quota.used||0)+'/'+(quota.unlimited?'â':String(quota.limit||0)); 4248 } 4249 function renderQuota(quota, target){ 4250 quota=quota||{}; 4251 var badge=qs('[data-pm-quota-badge]',root), panel=qs('[data-pm-quota-panel]',root), title=qs('[data-pm-quota-title]',root), help=qs('[data-pm-quota-help]',root), progress=qs('[data-pm-quota-progress]',root), bar=progress?qs('span',progress):null; 4252 if(badge){ badge.textContent=quota.unlimited?'Sınırsız konuÅma':String(quota.used||0)+' / '+String(quota.limit||0)+' konuÅma'; badge.classList.toggle('is-full',!!quota.reached); } 4253 if(panel) panel.classList.toggle('is-full',!!quota.reached); 4254 if(title) title.textContent=quota.unlimited?'Sınırsız':String(quota.remaining||0)+' yeni konuÅma hakkı kaldı'; 4255 if(help) help.textContent=quota.reached?'Yeni kullanıcıyla konuÅma baÅlatamazsınız; mevcut konuÅmalarınıza cevap verebilirsiniz.':'Aynı kullanıcıyla devam eden mesajlaÅmalar ek konuÅma hakkı kullanmaz.'; 4256 if(progress){ progress.hidden=!!quota.unlimited; if(bar) bar.style.width=String(parseInt(quota.percent||0,10)||0)+'%'; } 4257 var targetTitle=qs('[data-pm-target-quota-title]',root), targetHelp=qs('[data-pm-target-quota-help]',root), targetBox=qs('[data-pm-target-quota]',root); 4258 if(target && target.username){ 4259 if(targetTitle) targetTitle.textContent=quota.per_conversation_unlimited?'Sınırsız':String(quota.per_conversation_used||0)+' / '+String(quota.per_conversation_limit||0)+' mesaj'; 4260 if(targetHelp) targetHelp.textContent=quota.per_conversation_unlimited?'Bu konuÅmada mesaj sınırı yok.':String(quota.per_conversation_remaining||0)+' mesaj hakkı kaldı. KonuÅmadaki toplam mesaj: '+String(quota.conversation_total_messages||0)+'.'; 4261 if(targetBox) targetBox.classList.toggle('is-full',!!quota.per_conversation_reached); 4262 }else{ 4263 if(targetTitle) targetTitle.textContent='Alıcı seçildiÄinde gösterilir'; 4264 if(targetHelp) targetHelp.textContent='Bu kota, aynı kullanıcıya gönderdiÄiniz toplam mesaj sayısına göre hesaplanır.'; 4265 if(targetBox) targetBox.classList.remove('is-full'); 4266 } 4267 var submit=qs('[data-pm-submit]',root); 4268 if(submit && target && target.username){ submit.disabled=!!quota.per_conversation_reached || (!!quota.reached && !quota.has_conversation); } 4269 else if(submit){ submit.disabled=false; } 4270 } 4271 function applyPayload(payload){ 4272 if(!payload) return; 4273 if(payload.pagination){ 4274 if(payload.pagination.inbox && payload.pagination.inbox.page) root.setAttribute('data-pm-inbox-page',String(payload.pagination.inbox.page)); 4275 if(payload.pagination.sent && payload.pagination.sent.page) root.setAttribute('data-pm-sent-page',String(payload.pagination.sent.page)); 4276 } 4277 renderLists(payload); renderBlocks(payload.blocks); renderSummary(payload.summary,payload.quota); renderQuota(payload.quota,payload.target); 4278 } 4279 function poll(silent){ 4280 if(!liveUrl || polling || document.hidden) return; 4281 polling=true; 4282 var target=toInput ? toInput.value.trim() : ''; 4283 var url=liveUrl+(liveUrl.indexOf('?')===-1?'?':'&')+'to='+encodeURIComponent(target)+'&inbox_page='+encodeURIComponent(currentPage('inbox'))+'&sent_page='+encodeURIComponent(currentPage('sent'))+'&_='+Date.now(); 4284 request(url,{method:'GET'}).then(function(payload){ if(payload && payload.ok) applyPayload(payload); else if(!silent) showAlert(payload&&payload.message,false); }).catch(function(){ if(!silent) showAlert('Mesaj kutusu güncellenemedi.',false); }).finally(function(){ polling=false; }); 4285 } 4286 4287 root.addEventListener('click',function(e){ 4288 var reply=e.target.closest('[data-pm-reply-to]'); 4289 if(reply){ 4290 e.preventDefault(); 4291 if(toInput) toInput.value=reply.getAttribute('data-pm-reply-to')||''; 4292 if(subjectInput) subjectInput.value=reply.getAttribute('data-pm-reply-subject')||''; 4293 if(bodyInput) bodyInput.focus(); 4294 if(compose) compose.scrollIntoView({behavior:'smooth',block:'center'}); 4295 poll(true); return; 4296 } 4297 }); 4298 root.addEventListener('submit',function(e){ 4299 var form=e.target.closest('[data-pm-compose-form],[data-pm-action-form]'); if(!form) return; 4300 e.preventDefault(); 4301 var btn=e.submitter || qs('button[type="submit"],button:not([type])',form), old=btn?btn.textContent:''; 4302 if(btn){ btn.disabled=true; btn.textContent=form===compose?'Gönderiliyor...':'İÅleniyor...'; } 4303 postForm(form).then(function(payload){ 4304 if(payload && payload.ok){ applyPayload(payload); showAlert(payload.message||'İÅlem tamamlandı.',true); if(form===compose){ if(bodyInput) bodyInput.value=''; } else if(form.action.indexOf('/block')!==-1){ var u=qs('input[name="username"]',form); if(u) u.value=''; } } 4305 else showAlert(payload&&payload.message?payload.message:'İÅlem tamamlanamadı.',false); 4306 }).catch(function(){ showAlert('BaÄlantı hatası oluÅtu.',false); }).finally(function(){ if(btn){ btn.disabled=false; btn.textContent=old; } }); 4307 }); 4308 if(toInput){ 4309 toInput.addEventListener('input',function(){ window.clearTimeout(targetTimer); targetTimer=window.setTimeout(function(){ poll(true); },450); }); 4310 toInput.addEventListener('blur',function(){ poll(true); }); 4311 } 4312 document.addEventListener('visibilitychange',function(){ if(!document.hidden) poll(true); }); 4313 timer=window.setInterval(function(){ poll(true); },3000); 4314 poll(true); 4315 }
4316 function init(){ qsa('[data-pm-center]').forEach(setup); } 4317 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',init); else init(); 4318})(); 4319 4320 4321/* v1.1.44 - Yönetim menüsü arama + aktif baÄlantı */ 4322(function(){ 4323 function normalizeText(value){ 4324 try { return String(value || '').toLocaleLowerCase('tr-TR').trim(); } 4325 catch(e){ return String(value || '').toLowerCase().trim(); } 4326 } 4327 function initAdminMenuV144(){ 4328 var drawer = document.getElementById('adminSide'); 4329 if(!drawer || !drawer.classList.contains('admin-drawer-v144')) return; 4330 var input = drawer.querySelector('[data-admin-menu-search]'); 4331 var clear = drawer.querySelector('[data-admin-menu-search-clear]'); 4332 var empty = drawer.querySelector('[data-admin-menu-empty]'); 4333 var sections = Array.prototype.slice.call(drawer.querySelectorAll('[data-admin-menu-section]')); 4334 var links = Array.prototype.slice.call(drawer.querySelectorAll('.admin-nav-links-v144 a')); 4335 4336 var currentPath = (window.location.pathname || '').replace(/\/+$/, ''); 4337 var currentSearch = window.location.search || ''; 4338 var best = null; 4339 links.forEach(function(link){
4340 try { 4341 var u = new URL(link.href, window.location.origin); 4342 var path = u.pathname.replace(/\/+$/, ''); 4343 var pathMatch = path && (path === currentPath || currentPath.indexOf(path + '/') === 0); 4344 if(!pathMatch) return; 4345 var exactQuery = !!u.search && u.search === currentSearch; 4346 if(u.search && !exactQuery) return; 4347 var score = path.length + (exactQuery ? 10000 : 0) + (path === currentPath ? 1000 : 0); 4348 if(!best || score > best.score) best = {link:link, score:score}; 4349 } catch(e) {} 4350 }); 4351 if(best){ 4352 best.link.classList.add('active'); 4353 best.link.setAttribute('aria-current','page'); 4354 var activeSection = best.link.closest('details[data-admin-menu-section]'); 4355 var activeSubsection = best.link.closest('details[data-admin-menu-subsection]'); 4356 if(activeSection) activeSection.open = true; 4357 if(activeSubsection) activeSubsection.open = true; 4358 sections.forEach(function(section){ if(section.tagName === 'DETAILS' && section !== activeSection) section.open = false; }); 4359 } 4360 4361 function applyFilter(){ 4362 var q = normalizeText(input ? input.value : ''); 4363 var visibleCount = 0; 4364 sections.forEach(function(section){ 4365 var sectionLinks = Array.prototype.slice.call(section.querySelectorAll('.admin-nav-links-v144 a')); 4366 var sectionVisible = 0; 4367 sectionLinks.forEach(function(link){ 4368 var match = !q || normalizeText(link.textContent).indexOf(q) !== -1; 4369 link.hidden = !match; 4370 if(match){ sectionVisible++; visibleCount++; } 4371 }); 4372 var subsections = Array.prototype.slice.call(section.querySelectorAll('details[data-admin-menu-subsection]')); 4373 subsections.forEach(function(subsection){ 4374 var subLinks = Array.prototype.slice.call(subsection.querySelectorAll('a')); 4375 var subVisible = subLinks.some(function(link){ return !link.hidden; }); 4376 subsection.hidden = !subVisible; 4377 if(q && subVisible) subsection.open = true; 4378 }); 4379 section.hidden = sectionVisible === 0; 4380 if(q && sectionVisible > 0 && section.tagName === 'DETAILS') section.open = true; 4381 }); 4382 if(empty) empty.hidden = visibleCount !== 0; 4383 if(clear) clear.hidden = !q; 4384 } 4385 if(input){ 4386 input.addEventListener('input', applyFilter); 4387 input.addEventListener('keydown', function(e){ if(e.key === 'Escape'){ input.value=''; applyFilter(); input.blur(); } }); 4388 } 4389 if(clear){ clear.addEventListener('click', function(){ if(input){ input.value=''; input.focus(); } applyFilter(); }); } 4390 applyFilter(); 4391 } 4392 if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initAdminMenuV144); 4393 else initAdminMenuV144(); 4394})(); 4395 4396/* v1.1.58 - Webmaster teklif türü / ödeme planı alan görünürlüÄü */ 4397(function(){ 4398 function initOfferForm(form){ 4399 var type=form.querySelector('[data-offer-type]'); 4400 var pricing=form.querySelector('[data-service-pricing]'); 4401 var budgetLabel=form.querySelector('[data-budget-label]'); 4402 function syncType(){ 4403 var service=!type || type.value==='service_offer'; 4404 if(pricing) pricing.hidden=!service; 4405 if(budgetLabel){ 4406 var text=budgetLabel.childNodes[0]; 4407 if(text && text.nodeType===3) text.nodeValue=service?'Proje fiyatı':'Tahmini müÅteri bütçesi '; 4408 } 4409 var budget=form.querySelector('input[name="budget"]'); 4410 if(budget) budget.required=service; 4411 if(pricing) pricing.querySelectorAll('input,select,textarea').forEach(function(el){ el.disabled=!service; }); 4412 } 4413 if(type) type.addEventListener('change',syncType); 4414 syncType(); 4415 } 4416 function syncDeposit(root){ 4417 root.querySelectorAll('[data-payment-plan]').forEach(function(select){ 4418 function update(){ 4419 var scope=select.closest('form')||document; 4420 var field=scope.querySelector('.offer-deposit-field-v158'); 4421 if(field) field.hidden=select.value!=='milestone'; 4422 } 4423 select.addEventListener('change',update); update(); 4424 }); 4425 } 4426 function init(){ document.querySelectorAll('[data-webmaster-offer-form]').forEach(initOfferForm); syncDeposit(document); } 4427 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',init); else init(); 4428})(); 4429 4430/* v1.1.59 - Proje onay türüne göre aÅama / destek alanı görünürlüÄü */ 4431(function(){ 4432 function syncApprovalForm(select){ 4433 if(!select) return; 4434 var form=select.closest('form'); if(!form) return; 4435 var stage=form.querySelector('[data-approval-stage-v159]'); 4436 var support=form.querySelector('[data-approval-support-v159]'); 4437 var isFinal=select.value==='final_delivery'; 4438 if(stage) stage.hidden=isFinal;
4439 if(support) support.hidden=!isFinal; 4440 var stageSelect=stage?stage.querySelector('select[name="stage_id"]'):null; 4441 if(stageSelect) stageSelect.required=!isFinal; 4442 } 4443 document.querySelectorAll('[data-approval-type-v159]').forEach(function(select){ 4444 syncApprovalForm(select); 4445 select.addEventListener('change',function(){syncApprovalForm(select);}); 4446 }); 4447})(); 4448 4449 4450/* v1.1.63 - Talep / fiyat teklifi formu güvenli ve sürümler arası kalıcı sekme taslaÄı */ 4451(function(){ 4452 var STORAGE_KEY='wmt:webmaster-offer-form:v1'; 4453 var LEGACY_STORAGE_KEYS=['wmt:webmaster-offer-form:v1.1.62']; 4454 function storageGet(){ 4455 try{ 4456 var raw=sessionStorage.getItem(STORAGE_KEY); 4457 if(raw) return JSON.parse(raw); 4458 for(var i=0;i<LEGACY_STORAGE_KEYS.length;i++){ 4459 raw=sessionStorage.getItem(LEGACY_STORAGE_KEYS[i]); 4460 if(raw){ 4461 var parsed=JSON.parse(raw); 4462 try{ sessionStorage.setItem(STORAGE_KEY,raw); sessionStorage.removeItem(LEGACY_STORAGE_KEYS[i]); }catch(ignore){} 4463 return parsed; 4464 } 4465 } 4466 return null; 4467 }catch(e){ return null; } 4468 } 4469 function storageSet(data){ try{ sessionStorage.setItem(STORAGE_KEY,JSON.stringify(data)); }catch(e){} } 4470 function storageClear(){ 4471 try{ 4472 sessionStorage.removeItem(STORAGE_KEY); 4473 LEGACY_STORAGE_KEYS.forEach(function(key){sessionStorage.removeItem(key);}); 4474 }catch(e){} 4475 } 4476 function collect(form){ 4477 var data={savedAt:Date.now(),values:{}}; 4478 form.querySelectorAll('[name]').forEach(function(el){ 4479 var name=el.name||''; 4480 if(!name || name==='_csrf' || name==='_ffp_split_date[]' || el.type==='submit' || el.type==='button') return; 4481 if(el.type==='checkbox'){ 4482 if(!Array.isArray(data.values[name])) data.values[name]=[]; 4483 if(el.checked) data.values[name].push(el.value); 4484 return; 4485 } 4486 if(el.type==='radio'){ 4487 if(el.checked) data.values[name]=el.value; 4488 return; 4489 } 4490 data.values[name]=el.value; 4491 }); 4492 return data; 4493 } 4494 function restore(form,data){ 4495 if(!data || !data.values || typeof data.values!=='object') return false; 4496 var restored=false; 4497 form.querySelectorAll('[name]').forEach(function(el){ 4498 var name=el.name||''; 4499 if(!Object.prototype.hasOwnProperty.call(data.values,name)) return; 4500 var value=data.values[name]; 4501 if(el.type==='checkbox'){ 4502 el.checked=Array.isArray(value) && value.indexOf(el.value)!==-1; 4503 restored=true; return; 4504 } 4505 if(el.type==='radio'){ 4506 el.checked=String(value)===el.value; 4507 restored=true; return; 4508 } 4509 if(el.tagName==='SELECT'){ 4510 var exists=Array.prototype.some.call(el.options,function(opt){return opt.value===String(value);}); 4511 if(!exists) return; 4512 } 4513 el.value=value==null?'':String(value); restored=true; 4514 }); 4515 return restored; 4516 } 4517 function showRestoredNote(form,browserOnly){ 4518 var card=form.closest('.offer-form-card-v161')||document; 4519 var note=card.querySelector('[data-offer-draft-note]'); 4520 if(!note) return; 4521 note.hidden=false; 4522 if(browserOnly){ 4523 var strong=note.querySelector('strong'); var small=note.querySelector('small'); 4524 if(strong) strong.textContent='KaydedilmiÅ teklif taslaÄı geri yüklendi'; 4525 if(small) small.textContent='Bu sekmede daha önce girdiÄiniz bilgiler otomatik olarak geri getirildi.'; 4526 } 4527 } 4528 function init(form){ 4529 var clear=form.getAttribute('data-clear-browser-draft')==='1'; 4530 var serverDraft=form.getAttribute('data-server-draft')==='1'; 4531 var serverSavedAt=parseInt(form.getAttribute('data-server-draft-saved-at')||'0',10)||0; 4532 var hasPrefill=form.getAttribute('data-prefill-to')==='1'; 4533 if(clear) storageClear(); 4534 var draft=!clear&&!hasPrefill?storageGet():null; 4535 var browserIsNewer=draft && (!serverDraft || (parseInt(draft.savedAt||0,10)||0)>serverSavedAt); 4536 if(browserIsNewer && restore(form,draft)){ 4537 showRestoredNote(form,true); 4538 // Ãnceki sunucu doÄrulamasına ait alan iÅaretleri, daha yeni tarayıcı taslaÄında artık güncel olmayabilir. 4539 form.querySelectorAll('.has-error').forEach(function(el){el.classList.remove('has-error');}); 4540 form.querySelectorAll('.offer-field-error-v161').forEach(function(el){el.hidden=true;}); 4541 var summary=(form.closest('.offer-form-card-v161')||document).querySelector('.offer-form-error-summary-v161'); if(summary) summary.hidden=true; 4542 } else { 4543 // Sunucudan geri yüklenen formu da sekme taslaÄına eÅitle; yenilemede kaybolmasın. 4544 storageSet(collect(form)); 4545 } 4546 var timer=0; 4547 function clearStaleFieldError(target){ 4548 if(!target || !target.closest) return; 4549 var scope=target.closest('.has-error'); if(scope){ scope.classList.remove('has-error'); scope.querySelectorAll('.offer-field-error-v161').forEach(function(el){el.hidden=true;}); } 4550 var summary=(form.closest('.offer-form-card-v161')||document).querySelector('.offer-form-error-summary-v161'); if(summary) summary.hidden=true; 4551 } 4552 function schedule(e){ clearStaleFieldError(e&&e.target); clearTimeout(timer); timer=setTimeout(function(){storageSet(collect(form));},120); } 4553 form.addEventListener('input',schedule); 4554 form.addEventListener('change',schedule); 4555 form.addEventListener('submit',function(){ storageSet(collect(form)); }); 4556 var type=form.querySelector('[data-offer-type]'); if(type) type.dispatchEvent(new Event('change',{bubbles:true})); 4557 var plan=form.querySelector('[data-payment-plan]'); if(plan) plan.dispatchEvent(new Event('change',{bubbles:true})); 4558 } 4559 function boot(){ 4560 document.querySelectorAll('[data-offer-draft-v161]').forEach(init); 4561 document.querySelectorAll('[data-offer-draft-clear]').forEach(function(clearForm){ 4562 clearForm.addEventListener('submit',storageClear); 4563 }); 4564 } 4565 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',boot); else boot(); 4566})(); 4567 4568 4569/* v1.1.78 - Ãevrimiçi kullanıcı dizini hızlı filtre */ 4570(function(){ 4571 function normalize(value){ 4572 var text=String(value||'').trim(); 4573 try{return text.toLocaleLowerCase('tr-TR');}catch(e){return text.toLowerCase();} 4574 } 4575 function init(root){ 4576 var input=root.querySelector('[data-online-user-filter]'); 4577 if(!input) return; 4578 var cards=Array.prototype.slice.call(root.querySelectorAll('[data-online-user-card]')); 4579 var count=root.querySelector('[data-online-visible-count]'); 4580 var empty=root.querySelector('[data-online-filter-empty]'); 4581 function apply(){ 4582 var query=normalize(input.value); 4583 var visible=0; 4584 cards.forEach(function(card){ 4585 var show=!query || normalize(card.textContent).indexOf(query)!==-1; 4586 card.hidden=!show; 4587 if(show) visible++; 4588 }); 4589 if(count) count.textContent=String(visible); 4590 if(empty) empty.hidden=visible!==0; 4591 } 4592 input.addEventListener('input',apply); 4593 input.addEventListener('search',apply); 4594 apply(); 4595 } 4596 function boot(){document.querySelectorAll('[data-online-directory]').forEach(init);} 4597 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',boot); else boot(); 4598})(); 4599 4600/* v1.1.82 - Profesyonel ayarları banka hesabı seçimi ve güvenli IBAN kopyalama */ 4601(function(){ 4602 function syncBankField(form){ 4603 if(!form) return; 4604 var field=form.querySelector('[data-bank-account-field]'); 4605 if(!field) return; 4606 var check=form.querySelector('input[name="payment_methods[]"][value="bank_transfer"]'); 4607 var type=form.querySelector('[data-offer-type]'); 4608 var service=!type || type.value==='service_offer'; 4609 var enabled=!!check && check.checked && service; 4610 field.hidden=!enabled; 4611 var select=field.querySelector('select[name="bank_account_id"]'); 4612 if(select){ select.disabled=!enabled; select.required=enabled; } 4613 } 4614 function initForm(form){ 4615 if(!form || form.dataset.bankOfferReady==='1') return; 4616 form.dataset.bankOfferReady='1'; 4617 var check=form.querySelector('input[name="payment_methods[]"][value="bank_transfer"]'); 4618 var type=form.querySelector('[data-offer-type]'); 4619 if(check) check.addEventListener('change',function(){syncBankField(form);}); 4620 if(type) type.addEventListener('change',function(){syncBankField(form);}); 4621 syncBankField(form); 4622 } 4623 function copyValue(button){ 4624 var value=(button.getAttribute('data-bank-copy')||'').replace(/\s+/g,'').trim(); 4625 if(!value) return; 4626 var original=button.textContent; 4627 var done=function(){ button.textContent='Kopyalandı â'; button.classList.add('is-copied'); window.setTimeout(function(){button.textContent=original;button.classList.remove('is-copied');},1500); }; 4628 if(navigator.clipboard && navigator.clipboard.writeText){ navigator.clipboard.writeText(value).then(done).catch(function(){ fallback(value,done); }); } 4629 else fallback(value,done); 4630 } 4631 function fallback(value,done){ 4632 var ta=document.createElement('textarea'); ta.value=value; ta.setAttribute('readonly',''); ta.style.position='fixed'; ta.style.opacity='0'; document.body.appendChild(ta); ta.select(); 4633 try{ document.execCommand('copy'); }catch(e){} ta.remove(); done(); 4634 } 4635 function boot(){ 4636 document.querySelectorAll('form').forEach(function(form){ if(form.querySelector('[data-bank-account-field]')) initForm(form); }); 4637 } 4638 document.addEventListener('click',function(e){ var button=e.target.closest('[data-bank-copy]'); if(button){e.preventDefault();copyValue(button);} }); 4639 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',boot); else boot(); 4640})(); 4641 4642/* v1.1.86 - Mobil panelde önceki taÅmadan kalan kök yatay scroll konumunu sıfırla. */ 4643(function(){ 4644 'use strict'; 4645 function normalizePanelRootScroll(){ 4646 if(window.innerWidth > 980 || !document.body || !document.body.classList.contains('is-panel-area')) return; 4647 var root = document.scrollingElement || document.documentElement; 4648 if(root && root.scrollLeft !== 0) root.scrollLeft = 0; 4649 if(document.documentElement && document.documentElement.scrollLeft !== 0) document.documentElement.scrollLeft = 0; 4650 if(document.body.scrollLeft !== 0) document.body.scrollLeft = 0; 4651 } 4652 if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', normalizePanelRootScroll, {once:true}); 4653 else normalizePanelRootScroll(); 4654 window.addEventListener('pageshow', normalizePanelRootScroll, {passive:true}); 4655 window.addEventListener('orientationchange', function(){ setTimeout(normalizePanelRootScroll, 80); }, {passive:true}); 4656})(); 4657 4658 4659/* v1.1.87 - T.C. kimlik doÄrulama ana anahtarı: pasifte ilgili geliÅmiÅ ayarları kapat. */ 4660(function(){ 4661 'use strict'; 4662 function bootIdentitySettings(){ 4663 var root=document.querySelector('[data-identity-settings-root]'); 4664 if(!root) return; 4665 var toggle=root.querySelector('[data-identity-master-toggle]'); 4666 if(!toggle) return; 4667 var form=root.closest('form') || document; 4668 var dependents=Array.prototype.slice.call(form.querySelectorAll('[data-identity-dependent]')); 4669 var disabledNote=form.querySelector('[data-identity-disabled-note]'); 4670 var enabledNote=form.querySelector('[data-identity-enabled-note]'); 4671 var testButton=form.querySelector('[data-identity-test-button]'); 4672 var pill=root.querySelector('[data-identity-status-pill]'); 4673 root.classList.add('identity-ui-enhanced-v187'); 4674 function sync(){ 4675 var enabled=!!toggle.checked; 4676 root.classList.toggle('is-disabled-v187',!enabled);
4677 dependents.forEach(function(el){ el.hidden=!enabled; el.setAttribute('aria-hidden',enabled?'false':'true'); }); 4678 if(disabledNote) disabledNote.hidden=enabled; 4679 if(enabledNote) enabledNote.hidden=!enabled; 4680 if(testButton) testButton.hidden=!enabled; 4681 if(pill){ 4682 if(!enabled){ pill.textContent='â Normal baÅvuru modu'; pill.classList.remove('ok','warn'); pill.classList.add('off-v187'); } 4683 else { pill.classList.remove('off-v187'); pill.textContent='⢠Ayarları kaydedin'; pill.classList.add('warn'); } 4684 } 4685 } 4686 toggle.addEventListener('change',sync); 4687 sync(); 4688 } 4689 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',bootIdentitySettings,{once:true}); 4690 else bootIdentitySettings(); 4691})(); 4692 4693/* v1.1.89 - Profesyonel banka hesapları: kart baÅına tekrarlanan düzenleme formlarını tek ortak editörde birleÅtir. */ 4694(function(){ 4695 'use strict'; 4696 4697 function initProfessionalBankManager(root){ 4698 if(!root || root.dataset.bankManagerReady === '1') return; 4699 root.dataset.bankManagerReady = '1'; 4700 4701 var editor = root.querySelector('[data-bank-editor]'); 4702 var form = root.querySelector('[data-bank-editor-form]'); 4703 if(!editor || !form) return; 4704 4705 var title = root.querySelector('[data-bank-editor-title]'); 4706 var subtitle = root.querySelector('[data-bank-editor-subtitle]'); 4707 var submit = root.querySelector('[data-bank-editor-submit]'); 4708 4709 function field(name){ return form.querySelector('[data-bank-field="'+name+'"]'); } 4710 function setValue(name, value){ 4711 var el = field(name); 4712 if(!el) return; 4713 if(el.type === 'checkbox') el.checked = value === true || value === '1' || value === 1; 4714 else el.value = value == null ? '' : String(value); 4715 } 4716 function focusEditor(){ 4717 editor.open = true; 4718 window.requestAnimationFrame(function(){ 4719 try{ editor.scrollIntoView({behavior:'smooth', block:'start'}); }catch(e){ editor.scrollIntoView(); } 4720 var first = field('account_name'); 4721 if(first) window.setTimeout(function(){ try{ first.focus({preventScroll:true}); }catch(e){ first.focus(); } }, 260); 4722 }); 4723 } 4724 function resetNew(){ 4725 form.reset(); 4726 setValue('id','0'); 4727 setValue('account_name',''); 4728 setValue('bank_name',''); 4729 setValue('account_holder',''); 4730 setValue('iban',''); 4731 setValue('currency','TRY'); 4732 setValue('branch_name',''); 4733 setValue('account_number',''); 4734 setValue('swift_bic',''); 4735 var defaultField = field('is_default'); 4736 if(defaultField) defaultField.checked = root.querySelectorAll('[data-bank-editor-edit]').length === 0; 4737 if(title) title.textContent = 'ï¼ Yeni Banka Hesabı Ekle'; 4738 if(subtitle) subtitle.textContent = 'Tekliflerde kullanacaÄınız yeni hesabı güvenli biçimde tanımlayın.'; 4739 if(submit) submit.textContent = 'ï¼ Yeni Hesabı Kaydet'; 4740 form.classList.remove('is-editing'); 4741 } 4742 function loadEdit(button){ 4743 setValue('id', button.getAttribute('data-bank-id') || '0'); 4744 setValue('account_name', button.getAttribute('data-account-name') || ''); 4745 setValue('bank_name', button.getAttribute('data-bank-name') || ''); 4746 setValue('account_holder', button.getAttribute('data-account-holder') || ''); 4747 setValue('iban', button.getAttribute('data-iban') || ''); 4748 setValue('currency', button.getAttribute('data-currency') || 'TRY'); 4749 setValue('branch_name', button.getAttribute('data-branch-name') || ''); 4750 setValue('account_number', button.getAttribute('data-account-number') || ''); 4751 setValue('swift_bic', button.getAttribute('data-swift-bic') || ''); 4752 setValue('is_default', button.getAttribute('data-is-default') || '0'); 4753 var accountName = button.getAttribute('data-account-name') || 'Banka hesabı'; 4754 if(title) title.textContent = 'â ' + accountName + ' hesabını düzenle'; 4755 if(subtitle) subtitle.textContent = 'Yalnız seçtiÄiniz hesabın bilgileri bu tek düzenleme alanında gösterilir.'; 4756 if(submit) submit.textContent = 'â DeÄiÅiklikleri Kaydet'; 4757 form.classList.add('is-editing'); 4758 } 4759 4760 root.addEventListener('click', function(event){ 4761 var editButton = event.target.closest('[data-bank-editor-edit]'); 4762 if(editButton && root.contains(editButton)){ 4763 event.preventDefault(); 4764 loadEdit(editButton); 4765 focusEditor(); 4766 return; 4767 } 4768 var newButton = event.target.closest('[data-bank-editor-new]'); 4769 if(newButton && root.contains(newButton)){ 4770 event.preventDefault(); 4771 resetNew(); 4772 focusEditor(); 4773 return; 4774 } 4775 var cancelButton = event.target.closest('[data-bank-editor-cancel]'); 4776 if(cancelButton && root.contains(cancelButton)){ 4777 event.preventDefault(); 4778 resetNew(); 4779 editor.open = false;
4780 } 4781 }); 4782 } 4783 4784 function boot(){ 4785 document.querySelectorAll('[data-professional-bank-manager]').forEach(initProfessionalBankManager); 4786 } 4787 if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot); 4788 else boot(); 4789})(); 4790 4791 4792/* v1.1.91 - BirleÅik kullanıcı paneli menüsü: arama, aktif bölüm ve eriÅilebilir gruplar */ 4793(function(){ 4794 function normalize(value){ 4795 try { return String(value || '').toLocaleLowerCase('tr-TR').trim(); } 4796 catch(e){ return String(value || '').toLowerCase().trim(); } 4797 } 4798 function initUserMenuV191(){ 4799 var drawer=document.getElementById('userSide'); 4800 if(!drawer || !drawer.classList.contains('user-drawer-v191')) return; 4801 var input=drawer.querySelector('[data-user-menu-search]'); 4802 var clear=drawer.querySelector('[data-user-menu-search-clear]'); 4803 var empty=drawer.querySelector('[data-user-menu-empty]'); 4804 var groups=Array.prototype.slice.call(drawer.querySelectorAll('[data-user-menu-section]')); 4805 var links=Array.prototype.slice.call(drawer.querySelectorAll('.user-nav-links-v191 a')); 4806 var active=drawer.querySelector('.user-nav-links-v191 a.active'); 4807 if(active){ 4808 active.setAttribute('aria-current','page'); 4809 var activeGroup=active.closest('details[data-user-menu-section]'); 4810 if(activeGroup) activeGroup.open=true; 4811 } 4812 function filter(){ 4813 var q=normalize(input ? input.value : ''); 4814 var total=0; 4815 groups.forEach(function(group){ 4816 var count=0; 4817 Array.prototype.slice.call(group.querySelectorAll('.user-nav-links-v191 a')).forEach(function(link){ 4818 var ok=!q || normalize(link.textContent).indexOf(q)!==-1; 4819 link.hidden=!ok; 4820 if(ok){ count++; total++; } 4821 }); 4822 group.hidden=count===0; 4823 if(q && count>0) group.open=true; 4824 }); 4825 if(empty) empty.hidden=total!==0; 4826 if(clear) clear.hidden=!q; 4827 } 4828 if(input){ 4829 input.addEventListener('input',filter); 4830 input.addEventListener('keydown',function(e){ if(e.key==='Escape'){ input.value=''; filter(); input.blur(); } }); 4831 } 4832 if(clear) clear.addEventListener('click',function(){ if(input){ input.value=''; input.focus(); } filter(); }); 4833 filter(); 4834 } 4835 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',initUserMenuV191); 4836 else initUserMenuV191(); 4837})(); 4838 4839/* v1.1.91 - Panel özet akordeonlarına anchor ile gelindiÄinde ilgili kartı aç */ 4840(function(){ 4841 function openPanelAnchorV191(){ 4842 var id=(window.location.hash || '').replace(/^#/,''); 4843 if(!id) return; 4844 var node=document.getElementById(id); 4845 if(node && node.matches('details.panel-dashboard-detail-v191')) node.open=true; 4846 } 4847 window.addEventListener('hashchange',openPanelAnchorV191); 4848 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',openPanelAnchorV191); 4849 else openPanelAnchorV191(); 4850})(); 4851 4852/* v1.2.04 - Yönetim menüsü tek açık grup davranıÅı */ 4853(function(){ 4854 function initAdminAccordionV1204(){ 4855 var drawer=document.getElementById('adminSide'); 4856 if(!drawer || !drawer.classList.contains('admin-drawer-v1204')) return; 4857 var search=drawer.querySelector('[data-admin-menu-search]'); 4858 var groups=Array.prototype.slice.call(drawer.querySelectorAll('details.admin-nav-group-v1204')); 4859 groups.forEach(function(group){ 4860 group.addEventListener('toggle',function(){ 4861 if(!group.open) return; 4862 if(search && String(search.value||'').trim()!=='') return; 4863 groups.forEach(function(other){ if(other!==group && other.open) other.open=false; }); 4864 }); 4865 }); 4866 } 4867 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',initAdminAccordionV1204); else initAdminAccordionV1204(); 4868})(); 4869 4870/* v1.2.08 - Açılan yan menü grubunu görünür alanda tut */ 4871(function(){ 4872 function menuHasSearch(drawer){ 4873 var input=drawer && drawer.querySelector('[data-admin-menu-search],[data-user-menu-search]'); 4874 return !!(input && String(input.value||'').trim()); 4875 } 4876 function revealInside(nav,node){ 4877 if(!nav || !node) return; 4878 /* Kullanıcı paneli masaüstünde menü sayfa akıÅındadır; ayrı scrollTop yönetilmez. */ 4879 var drawer=nav.closest && nav.closest('.side-menu'); 4880 if(drawer && drawer.id==='userSide' && window.matchMedia && window.matchMedia('(min-width: 981px)').matches) return; 4881 window.requestAnimationFrame(function(){ 4882 var nr=nav.getBoundingClientRect(); 4883 var rr=node.getBoundingClientRect(); 4884 var pad=8; 4885 if(rr.height >
4885 nr.height-(pad*2)){ 4886 nav.scrollTop += rr.top-nr.top-pad; 4887 return; 4888 } 4889 if(rr.top < nr.top+pad) nav.scrollTop -= (nr.top+pad-rr.top); 4890 else if(rr.bottom > nr.bottom-pad) nav.scrollTop += (rr.bottom-(nr.bottom-pad)); 4891 }); 4892 } 4893 function bindDrawer(drawer,navSelector,groupSelector,subgroupSelector){ 4894 if(!drawer) return; 4895 var nav=drawer.querySelector(navSelector); 4896 if(!nav) return; 4897 var groups=Array.prototype.slice.call(drawer.querySelectorAll(groupSelector)); 4898 groups.forEach(function(group){ 4899 group.addEventListener('toggle',function(){ 4900 if(!group.open) return; 4901 if(!menuHasSearch(drawer)){ 4902 groups.forEach(function(other){ if(other!==group && other.open) other.open=false; }); 4903 } 4904 revealInside(nav,group); 4905 }); 4906 }); 4907 if(subgroupSelector){ 4908 Array.prototype.slice.call(drawer.querySelectorAll(subgroupSelector)).forEach(function(subgroup){ 4909 subgroup.addEventListener('toggle',function(){ 4910 if(!subgroup.open) return; 4911 revealInside(nav,subgroup.querySelector('summary') || subgroup); 4912 }); 4913 }); 4914 } 4915 var active=drawer.querySelector('a[aria-current="page"],a.active'); 4916 if(active){ 4917 window.requestAnimationFrame(function(){ revealInside(nav,active); }); 4918 } 4919 } 4920 function initSidebarVisibilityV1208(){ 4921 bindDrawer(document.getElementById('adminSide'),'.admin-nav-v144','details.admin-nav-group-v1204','details.admin-nav-subgroup-v1207'); 4922 bindDrawer(document.getElementById('userSide'),'.user-nav-v191','details.user-nav-group-v191',null); 4923 } 4924 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',initSidebarVisibilityV1208); 4925 else initSidebarVisibilityV1208(); 4926})(); 4927 4928/* v1.2.17 - Hesap güvenliÄi: güvenli kopyalama ve kritik iÅlem onayı */ 4929(function(){ 4930 'use strict'; 4931 function fallbackCopy(value, done){ 4932 var ta=document.createElement('textarea'); 4933 ta.value=value; ta.setAttribute('readonly',''); ta.style.position='fixed'; ta.style.opacity='0'; ta.style.pointerEvents='none'; 4934 document.body.appendChild(ta); ta.select(); 4935 try{ document.execCommand('copy'); }catch(e){} 4936 ta.remove();
4936 if(done) done(); 4937 } 4938 function copy(button){ 4939 var value=(button.getAttribute('data-copy-value')||'').trim(); 4940 if(!value) return; 4941 var original=button.textContent; 4942 var done=function(){ button.textContent='Kopyalandı â'; button.classList.add('is-copied'); window.setTimeout(function(){button.textContent=original;button.classList.remove('is-copied');},1600); }; 4943 if(navigator.clipboard && navigator.clipboard.writeText){ navigator.clipboard.writeText(value).then(done).catch(function(){fallbackCopy(value,done);}); } 4944 else fallbackCopy(value,done); 4945 } 4946 document.addEventListener('click',function(e){ 4947 var stopNode=e.target.closest('[data-stop-propagation]'); 4948 if(stopNode){ e.stopPropagation(); } 4949 var copyButton=e.target.closest('[data-copy-value]'); 4950 if(copyButton){ e.preventDefault(); copy(copyButton); return; } 4951 // Formların onayı submit olayında tek kez ele alınır. Böylece klavye ile submit, 4952 // programatik requestSubmit ve normal buton tıklaması aynı güvenli davranıÅı kullanır. 4953 var confirmButton=e.target.closest('button[data-confirm],a[data-confirm],[role="button"][data-confirm]'); 4954 if(confirmButton){ 4955 var message=(confirmButton.getAttribute('data-confirm')||'Bu iÅlemi gerçekleÅtirmek istediÄinizden emin misiniz?').trim(); 4956 if(!window.confirm(message)){ e.preventDefault(); e.stopPropagation(); } 4957 } 4958 }); 4959 document.addEventListener('submit',function(e){ 4960 var form=e.target && e.target.closest ? e.target.closest('form[data-confirm]') : null; 4961 if(!form) return; 4962 var message=(form.getAttribute('data-confirm')||'Bu iÅlemi gerçekleÅtirmek istediÄinizden emin misiniz?').trim(); 4963 if(!window.confirm(message)){ e.preventDefault(); e.stopPropagation(); } 4964 }); 4965})(); 4966 4967 4968/* v1.2.19 - CSP uyumlu etkileÅimler + geliÅmiŠüç durumlu tema: Açık â Koyu â Otomatik. */
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.