PageSourceSearch

https://webmasterturkiye.com/themes/default/assets/app.js?v=1.2.27

js webmasterturkiye.com collected 2026-10-08 11:06:32 UTC 251,795 bytes, 4,968 lines download raw bytes

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 ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[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 ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[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 ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[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,'&quot;')+'" 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 ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[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 {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[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 ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[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 ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[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 = '&lt;/&gt; 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 ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[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.