Ana Logo (Header - Sol Üst)
Site başlığındaki ana logo görseli (PNG formatında, şeffaf arka plan önerilir)
Logo için SEO açıklaması
${header.logoSrc ? `
${header.logoAlt || 'Logo'}

Header'da nasıl görüneceği

Son güncelleme: ${new Date().toLocaleString('tr-TR')}
` : `
Logo Eksik!
Site logosu ayarlanmamış. Lütfen bir logo yükleyin.
`}
Hero Bölümü Ana Görseli (Sağ Taraf)
Ana sayfa hero bölümünün sağ tarafındaki büyük görsel
SEO ve erişilebilirlik için görsel açıklaması
${hero.heroImage?.src ? `
${hero.heroImage.alt || 'Hero Görsel'}

Hero bölümünde nasıl görüneceği

` : ''}
Ana Sayfa Arka Plan Görseli
Ana sayfanın hero bölümündeki arka plan görseli
Arka plan için SEO açıklaması
${background.mainBg ? `

HERO BÖLÜMÜ

Arka plan görseli nasıl görünecek

Ana sayfa hero bölümünde nasıl görüneceği

Son güncelleme: ${new Date().toLocaleString('tr-TR')}
` : `
Arka Plan Eksik!
Ana sayfa arka plan görseli ayarlanmamış. Lütfen bir arka plan yükleyin.
`}
Mobil Uygulama Görseli
Mobil uygulama bölümündeki görsel
SEO için mobil app görsel açıklaması
${mobileApp.image?.src ? `
${mobileApp.image.alt || 'Mobile App'}

Mobil app bölümünde nasıl görüneceği

` : ''}
Oyun Kategorileri Bölümü Arka Planı
Oyun kategorileri bölümünün genel arka plan görseli
SEO için arka plan görsel açıklaması
${gameCategories.background?.src ? `

OYUN KATEGORİLERİ BÖLÜMÜ

Genel arka plan görseli

Slot Oyunları
Canlı Casino

Oyun kategorileri bölümünde nasıl görüneceği

Son güncelleme: ${new Date().toLocaleString('tr-TR')}
` : `
Oyun Kategorileri Arka Planı Eksik!
Oyun kategorileri bölümü arka plan görseli ayarlanmamış. Lütfen bir arka plan yükleyin.
`}
Oyun Kategori Kartları Görselleri
${(gameCategories.cards || []).map((card, index) => `

Kategori ${index + 1}: ${card.title_line1 || 'Başlık'} ${card.title_line2 || ''}

Bu kategorinin özel arka plan görseli
SEO için kategori görsel açıklaması
${card.background?.src ? `

${card.title_line1 || 'BAŞLIK'}
${card.title_line2 || 'ALT BAŞLIK'}

` : ''}
`).join('')}
Oyun kategorisi eklemek için "Oyun Kategorileri" bölümünü kullanın
Hakkımızda Bölümü Arka Planı
Hakkımızda bölümünün arka plan görseli
SEO için arka plan görsel açıklaması
${about.background?.src ? `

HAKKIMIZDA

Eğlencenin ve kazancın adresi X'e hoş geldiniz. Güvenilir casino deneyimi...

Hakkımızda bölümünde nasıl görüneceği

Son güncelleme: ${new Date().toLocaleString('tr-TR')}
` : `
Hakkımızda Arka Planı Eksik!
Hakkımızda bölümü arka plan görseli ayarlanmamış. Lütfen bir arka plan yükleyin.
`}
SEO ve Sosyal Medya Görselleri
Facebook, LinkedIn ve diğer sosyal medya platformları için (1200x630px önerilir)
Sosyal medyada paylaşıldığında görsel açıklaması
${openGraph.image ? `
${openGraph.imageAlt || 'Social Media'}

Facebook, Twitter, LinkedIn'de nasıl görüneceği

` : ''}
Favicon ve Site İkonları
16x16 ve 32x32 boyutlarında ICO dosyası ${favicon.ico ? `
Favicon Mevcut favicon
` : ''}
16x16 piksel PNG favicon ${favicon.png16 ? `
Favicon 16x16 Mevcut 16x16 PNG
` : ''}
32x32 piksel PNG favicon ${favicon.png32 ? `
Favicon 32x32 Mevcut 32x32 PNG
` : ''}
180x180 piksel Apple cihazları için ${favicon.appleTouch ? `
Apple Touch Icon Mevcut Apple Touch Icon
` : ''}
${(favicon.ico || favicon.png16 || favicon.png32 || favicon.appleTouch) ? `
${favicon.ico ? `
ICO Favicon
ICO
` : ''} ${favicon.png16 ? `
PNG 16x16
16x16
` : ''} ${favicon.png32 ? `
PNG 32x32
32x32
` : ''} ${favicon.appleTouch ? `
Apple Touch
Apple Touch
` : ''}
Tarayıcı sekmesinde ve yer imlerinde görünecek
` : `
Favicon Eksik!
Site ikonu henüz ayarlanmamış. En az bir favicon yükleyin.
`}
`; } function buildContentSection() { const hero = currentConfig.hero || {}; const marquee = currentConfig.marquee || {}; const mobileApp = currentConfig.mobileApp || {}; const about = currentConfig.about || {}; return `
İçerik Yönetimi
Ana Sayfa İçerikleri
Kayan Duyuru Bandı
Mobil Uygulama Bölümü
Hakkımızda Bölümü
HTML etiketleri kullanabilirsiniz: <p>, <br>, <strong>
`; } function buildDesignSection() { const design = currentConfig.design || {}; return `
Tasarım & Renkler
Ana Renk Paleti
Site genelinde kullanılan ana kırmızı renk
Buton ve link hover efekt rengi
Sitenin genel arka plan rengi
Canlı Renk Önizlemesi
Ana Renk
Butonlar ve vurgular
Hover Rengi
Üzerine gelme efekti
Arka Plan
Site arka planı
Test Butonları:
Gerçek Zamanlı Uygulama:
Renk değişiklikleri anında uygulanır. Kaydetmek için "Tasarım Değişikliklerini Kaydet" butonuna tıklayın. Değişiklikler tüm siteye otomatik olarak yansıyacaktır.
Yazı Tipleri ve Boyutları
Ana sayfa başlık font boyutu
Genel metin font boyutu
Arka Plan Görselleri
Görselin URL'sini girin veya /img/ klasöründeki dosya yolunu yazın
`; } function buildSeoSection() { // 🐦 TWITTER CREATOR FIX: Ensure seo.twitter structure exists if (!currentConfig.seo) { currentConfig.seo = {}; } if (!currentConfig.seo.twitter) { currentConfig.seo.twitter = {}; } const seo = currentConfig.seo || {}; const meta = seo.meta || {}; const openGraph = seo.openGraph || {}; const twitter = seo.twitter || {}; const tracking = seo.tracking || {}; console.log('🐦 Twitter Creator Debug - current value:', twitter.creator); return `
SEO Ayarları
Temel SEO Ayarları
Google'da görünecek ana başlık (maksimum 60 karakter)
Google'da görünecek açıklama (maksimum 160 karakter)
Virgülle ayırarak yazın
Sosyal Medya Paylaşım (Open Graph)
Twitter Card Ayarları
Takip Kodları (Analytics)
`; } function buildAmpSection() { const amp = currentConfig.amp || {}; return `
AMP Ayarları
AMP (Accelerated Mobile Pages) Yapılandırması
Yerel dosya için: index.amp.php
Uzak URL için: https://example.com/amp-sayfasi
AMP Nedir?
AMP (Accelerated Mobile Pages), mobil cihazlarda sayfalarınızın çok hızlı yüklenmesini sağlayan Google teknolojisidir. SEO performansınızı artırır ve mobil kullanıcı deneyimini iyileştirir.
`; } function buildSocialSection() { const header = currentConfig.header || {}; const social = header.social || []; return `
Sosyal Medya Ayarları
Header Sosyal Medya Linkleri
Site üst kısmında görünecek sosyal medya hesap linkleri. Boş bırakılan linkler görünmeyecektir.
Nasıl Çalışır?
• URL alanlarını doldurun, boş bırakılan sosyal medya hesapları görünmeyecektir
• Linkler site üst kısmında ikonlar halinde görünür
• Değişiklikler kaydetildikten sonra anında aktif olur
• Tüm linkler yeni sekmede açılır (_blank)
Sosyal Medya Ayarları
İkonlar üzerine gelindiğinde renk değişimi
Önizleme
Mevcut sosyal medya linklerinizin önizlemesi:
${social.map(item => { if (item && item.url) { return ` `; } return ''; }).join('')} ${social.filter(item => item && item.url).length === 0 ? 'Henüz sosyal medya linki eklenmemiş' : ''}
`; } // Placeholder functions for other sections function buildGamesSection() { const gameCategories = currentConfig.gameCategories || {}; const cards = gameCategories.cards || []; return `
Oyun Kategorileri Yönetimi
Genel Arka Plan Ayarları
Oyun kategorileri bölümünün genel arka plan görseli
${cards.map((card, index) => `
Oyun Kategorisi ${index + 1}: ${card.title ? card.title.replace(/
/g, ' ') : 'Yeni Kategori'}
Başlığın ilk satırı (büyük harflerle yazın)
Başlığın ikinci satırı (büyük harflerle yazın)
Bu kategorinin özel arka plan görseli URL'si
SEO için görsel açıklaması
Kart üzerindeki buton yazısı
Butona tıklandığında gidilecek URL
Kart Önizlemesi:

${card.title_line1 || card.title?.split('
')[0] || 'BAŞLIK'}
${card.title_line2 || card.title?.split('
')[1] || 'ALT BAŞLIK'}

`).join('')}
Yeni Oyun Kategorisi Ekle

Maksimum 6 oyun kategorisi ekleyebilirsiniz

Tam Bölüm Önizlemesi
${cards.map(card => `

${card.title_line1 || card.title?.split('
')[0] || 'BAŞLIK'}
${card.title_line2 || card.title?.split('
')[1] || 'ALT BAŞLIK'}

`).join('')}
`; } function buildPaymentSection() { const footer = currentConfig.footer || {}; const payments = footer.payments || []; return `
Ödeme Sistemleri Yönetimi
Bölüm Başlığı Ayarları
Ödeme yöntemleri bölümünün üst başlık metni
${payments.map((payment, index) => `
Ödeme Yöntemi ${index + 1}: ${payment.alt || 'İsimsiz Ödeme Yöntemi'}
SEO ve erişilebilirlik için logo açıklaması
PNG formatında logo dosyasının yolu
${payment.img ? `
Logo Önizlemesi:
${payment.alt}
` : `
Logo URL'si girildikten sonra önizleme burada görünecek
`}
`).join('')}
Yeni Ödeme Yöntemi Ekle

Maksimum 10 ödeme yöntemi ekleyebilirsiniz

Tam Bölüm Önizlemesi

${footer.payment_title || 'GÜVENLİ ÖDEME YÖNTEMLERİ'}

${payments.length > 0 ? payments.map(payment => `
${payment.img ? `${payment.alt}` : `
${payment.alt || 'Logo Eksik'}
`}
`).join('') : '
Henüz ödeme yöntemi eklenmemiş
'}
Kullanım Bilgileri
Önerilen Logo Özellikleri:
  • • Format: PNG (şeffaf arka plan)
  • • Boyut: Minimum 200x80px, Maksimum 400x160px
  • • Dosya boyutu: Maksimum 100KB
  • • Yatay düzen tercih edilir
  • • Yüksek çözünürlük (2x) önerilir
`; } function buildAdvancedSection() { const advanced = currentConfig.advanced || {}; const security = advanced.security || {}; const performance = advanced.performance || {}; const system = advanced.system || {}; const email = advanced.email || {}; const backup = advanced.backup || {}; const legal = advanced.legal || {}; const custom = advanced.custom || {}; return `
Gelişmiş Sistem Ayarları
Güvenlik ve Koruma Ayarları
Aynı IP'den dakika başına maksimum istek sayısı
Hesap kilitlenmesi için maksimum yanlış giriş
Engellenmiş IP'nin bekleme süresi
Tüm HTTP isteklerini HTTPS'e yönlendir
Bu IP adreslerinden gelen istekler engellenecek
Performans ve Optimizasyon
Sayfa boyutunu %70'e kadar küçültür
Statik dosyalar için cache süresi
Görselleri gerektiğinde yükle
Statik dosyalar için CDN adresi
Site Durumu ve Genel Ayarlar
Site ziyaretçiler için kapatılır
Hata mesajlarını göster (sadece geliştirme)
E-posta ve Bildirim Ayarları
Sistem bildirimleri bu adrese gönderilecek
Yedekleme ve Geri Yükleme
Günlük otomatik veritabanı yedeği
Eski yedekler otomatik silinir
Özel Kod Ekleme
Bu kodlar sitenin <head> bölümüne eklenecek
Bu kodlar sayfanın sonuna eklenecek
Google Tag Manager container ID'si
Lisans ve Yasal Uyarılar
Sistem Bilgileri ve Durum
PHP Versiyonu
7.4.33
Server Yazılımı
LiteSpeed
Disk Kullanımı
85GB
Güvenlik Durumu:
✅ SSL Sertifikası Aktif
✅ Güvenlik Başlıkları Yapılandırıldı
✅ Rate Limiting Aktif
✅ Brute Force Koruması Aktif
`; } function buildFooterSection() { const footer = currentConfig.footer || {}; const columns = footer.columns || []; return `
Footer Yönetimi
Logo ve Açıklama Bölümü
Logo altında görünecek açıklama metni
${columns.map((column, columnIndex) => `
${column.title || `Kolon ${columnIndex + 1}`}
Bu kolonun üst başlığı
${(column.links || []).map((link, linkIndex) => `
`).join('')}
${(column.logos || []).map((logo, logoIndex) => `
`).join('')}
${(column.logos || []).length > 0 ? `
Logo Önizlemesi:
${column.logos.map(logo => ` ${logo.alt} `).join('')}
` : ''}
`).join('')}
Yeni Footer Kolonu Ekle

Maksimum 4 kolon önerilir

Copyright ve Alt Bilgiler
Footer'ın en alt kısmında görünecek telif hakkı metni
Footer Önizlemesi

${footer.payment_title || 'GÜVENLİ ÖDEME YÖNTEMLERİ'}

${(footer.payments || []).map(payment => ` ${payment.alt} `).join('')}
LOGO

${footer.about_text || 'Footer açıklama metni buraya gelecek...'}

${Array(5).fill(0).map(() => '
').join('')}
${columns.map(column => `
${column.title || 'Kolon Başlığı'}
    ${(column.links || []).map(link => `
  • ${link.text}
  • `).join('')} ${(column.logos || []).length > 0 ? `
  • ${column.logos.map(logo => ` ${logo.alt} `).join('')}
  • ` : ''}
`).join('')}
${footer.copyright || 'Copyrights © 2019 Kareasbet. Tüm Hakları Saklıdır.'}
`; } async function initializeAdminPanel() { console.log('🔧 initializeAdminPanel başlatılıyor...'); // Load admin functions from database first try { console.log('📦 Database admin functions loading...'); await loadAdminFunctionsFromDB(); console.log('✅ Database admin functions loaded'); } catch (error) { console.warn('⚠️ Database admin functions failed, loading emergency functions:', error); loadEmergencyAdminFunctions(); } // Ensure all critical functions are available globally const criticalFunctions = { showSection: typeof showSection !== 'undefined' ? showSection : function(section) { console.log('🔄 Switching to section:', section); currentSection = section; document.querySelectorAll('.admin-nav-item').forEach(item => item.classList.remove('active')); const navItem = document.querySelector(`[data-section="${section}"]`); if (navItem) navItem.classList.add('active'); buildAdminSection(section); }, logout: typeof logout !== 'undefined' ? logout : function() { window.location.href = 'index.php?logout=true'; }, buildAdminSection: typeof buildAdminSection !== 'undefined' ? buildAdminSection : function(section) { console.log('🏗️ Building admin section:', section); const container = document.getElementById('admin-sections'); let html = ''; switch(section) { case 'dashboard': html = (typeof buildDashboard !== 'undefined') ? buildDashboard() : '

Dashboard

Dashboard loading...

'; break; case 'content': html = (typeof buildContentSection !== 'undefined') ? buildContentSection() : '

Content

Content section loading...

'; break; case 'visuals': html = (typeof buildVisualsSection !== 'undefined') ? buildVisualsSection() : '

Visuals

Visuals section loading...

'; break; case 'menu': html = (typeof buildMenuSection !== 'undefined') ? buildMenuSection() : '

Menu

Menu section loading...

'; break; case 'design': html = (typeof buildDesignSection !== 'undefined') ? buildDesignSection() : '

Design

Design section loading...

'; break; case 'seo': html = (typeof buildSeoSection !== 'undefined') ? buildSeoSection() : '

SEO

SEO section loading...

'; break; case 'social': html = (typeof buildSocialSection !== 'undefined') ? buildSocialSection() : '

Social

Social section loading...

'; break; case 'games': html = (typeof buildGamesSection !== 'undefined') ? buildGamesSection() : '

Games

Games section loading...

'; break; case 'payment': html = (typeof buildPaymentSection !== 'undefined') ? buildPaymentSection() : '

Payment

Payment section loading...

'; break; case 'footer': html = (typeof buildFooterSection !== 'undefined') ? buildFooterSection() : '

Footer

Footer section loading...

'; break; case 'amp': html = (typeof buildAmpSection !== 'undefined') ? buildAmpSection() : '

AMP

AMP section loading...

'; break; case 'advanced': html = (typeof buildAdvancedSection !== 'undefined') ? buildAdvancedSection() : '

Advanced

Advanced section loading...

'; break; default: html = '

Unknown Section

Section not found: ' + section + '

'; } if (container) { container.innerHTML = html; console.log('✅ Admin section built:', section); } else { console.error('❌ Admin sections container not found'); } } }; // Make all functions globally available Object.assign(window, criticalFunctions); // Initialize form state management console.log('🔧 Form state management başlatılıyor...'); if (typeof formStateCache === 'undefined') { window.formStateCache = {}; } // Additional functions - only if they exist const additionalFunctions = [ 'addGameCategory', 'removeGameCategory', 'createBackup', 'downloadConfig', 'clearCache', 'addFooterColumn', 'removeFooterColumn', 'addFooterLink', 'removeFooterLink', 'addFooterLogo', 'removeFooterLogo', 'setTestLogo', 'saveChanges', 'validateAdminData', 'restoreDefaultData' ]; additionalFunctions.forEach(funcName => { if (typeof window[funcName] !== 'undefined') { // Function already exists, keep it } else { // Create placeholder window[funcName] = function(...args) { console.warn(`⚠️ Function ${funcName} not fully loaded, args:`, args); alert(`Fonksiyon "${funcName}" henüz yüklenmedi. Lütfen sayfayı yenileyin.`); }; } }); console.log('🎯 Building initial dashboard...'); window.buildAdminSection('dashboard'); console.log('🔗 Setting up navigation...'); // Admin navigation event listeners document.querySelectorAll('.admin-nav-item').forEach(item => { item.addEventListener('click', function(e) { e.preventDefault(); const section = this.getAttribute('data-section'); if (section) { showSection(section); } }); }); // Quick actions event listeners document.addEventListener('click', function(e) { if (e.target.closest('[data-action]')) { const action = e.target.closest('[data-action]').getAttribute('data-action'); switch(action) { case 'content': case 'visuals': case 'design': case 'seo': showSection(action); break; case 'view': window.open('index.php', '_blank'); break; case 'logout': logout(); break; } } }); } // Removed: Debug functions (production version) async function saveChanges() { console.log('🚀 === SAVE CHANGES STARTED ==='); let newConfig = null; // EMERGENCY RECOVERY WRAPPER try { // 1. ÖNCE TOKEN'I YENİLE - Bu problemi çözecek! console.log('🔄 CSRF token yenileniyor...'); try { await refreshCSRFToken(); } catch (tokenError) { console.error('❌ Token yenileme hatası:', tokenError); throw new Error('CSRF token yenileme başarısız: ' + tokenError.message); } // 2. Yenilenmiş token'ı al const csrfMetaTag = document.querySelector('meta[name="csrf-token"]'); const csrfToken = csrfMetaTag?.getAttribute('content'); console.log('🔐 CSRF Token (yenilenmiş):', csrfToken ? '✅ Found' : '❌ Missing'); if (!csrfToken) { throw new Error('Güvenlik token\'ı bulunamadı veya yenilenemedi'); } // 2. Güvenli config kopyalama newConfig = safeDeepClone(currentConfig); console.log('📋 Config cloned safely. Keys:', Object.keys(newConfig)); // 3. Form verilerini güvenli şekilde topla console.log('📝 Collecting form data...'); let formData; try { formData = collectFormData(); console.log('📊 Form data collected:', Object.keys(formData)); // Form data validation if (!formData || typeof formData !== 'object') { throw new Error('Form verisi toplanamadı veya geçersiz format'); } } catch (formError) { console.error('❌ Form data toplama hatası:', formError); throw new Error('Form verilerinde hata: ' + formError.message); } // 4. Config'i güvenli şekilde güncelle try { newConfig = safeUpdateConfig(currentConfig, formData); console.log('🔄 Config updated safely'); // Config validation if (!newConfig || typeof newConfig !== 'object') { throw new Error('Config güncelleme sonucu geçersiz'); } } catch (configError) { console.error('❌ Config güncelleme hatası:', configError); throw new Error('Config güncellemesi başarısız: ' + configError.message); } // 5. Verileri validate et const validation = validateConfig(newConfig); if (!validation.valid) { throw new Error('❌ Config validation failed: ' + validation.errors.join(', ')); } console.log('✅ Config validation passed'); // 6. API'ye güvenli gönderim console.log('📤 Sending to API...'); let response; try { // JSON serialization test BEFORE sending const testJson = JSON.stringify(newConfig); if (!testJson || testJson.length === 0) { throw new Error('Config JSON serileştirilemedi'); } response = await safeSendToAPI(newConfig, csrfToken); if (!response) { throw new Error('API\'den yanıt alınamadı'); } } catch (apiError) { console.error('❌ API gönderim hatası:', apiError); throw new Error('API iletişim hatası: ' + apiError.message); } if (response.success) { console.log('🎉 SAVE SUCCESSFUL!'); // Config'i güncelle currentConfig = newConfig; siteConfig = newConfig; // Public page'i güncelle renderPublicPage(newConfig); // HEMEN token'ı yenile - Bir sonraki kaydetme için console.log('🔄 Başarılı kaydetmeden sonra token yenileniyor...'); await refreshCSRFToken(); // Başarı mesajını göster alert('✅ Değişiklikler başarıyla kaydedildi!\n\n🔑 Admin panel bir sonraki değişiklik için hazır!'); // Cache problemini çözmek için anasayfayı yenile setTimeout(() => { console.log('🔄 Cache problemini önlemek için anasayfa yenileniyor...'); // Anasayfayı yeni sekmede aç ki admin panel kapanmasın const newTab = window.open('index.php?t=' + Date.now(), '_blank'); if (newTab) { newTab.focus(); } else { // Popup blocker varsa bu şekilde çözüm console.log('📱 Popup engellendi, manuel yenileme önerisi gösteriliyor'); showCacheRefreshNotification(); } }, 2000); } else { throw new Error(response.error || 'API kaydetme hatası'); } } catch (error) { console.error('💥 SAVE ERROR:', error); console.error('💥 Error Stack:', error.stack); // EMERGENCY RECOVERY MODE const errorMessage = error.message || 'Bilinmeyen hata'; // Error categorization for better handling let recoveryOptions = []; let autoRecovery = false; if (errorMessage.includes('CSRF') || errorMessage.includes('token') || errorMessage.includes('403')) { console.log('🔧 CSRF/Token error detected'); recoveryOptions.push('🔑 Token yenile ve tekrar dene'); recoveryOptions.push('🔄 Debug mode ile kaydet'); autoRecovery = true; } else if (errorMessage.includes('JSON') || errorMessage.includes('parse')) { console.log('🔧 JSON error detected'); recoveryOptions.push('📝 Form verilerini temizle'); recoveryOptions.push('🔄 Debug mode ile kaydet'); } else if (errorMessage.includes('API') || errorMessage.includes('network') || errorMessage.includes('fetch')) { console.log('🔧 Network error detected'); recoveryOptions.push('🌐 Bağlantıyı kontrol et'); recoveryOptions.push('🔄 Debug mode ile kaydet'); autoRecovery = true; } else if (errorMessage.includes('Form') || errorMessage.includes('data')) { console.log('🔧 Form data error detected'); recoveryOptions.push('📝 Formu yenile'); recoveryOptions.push('🔄 Sayfayı yenile'); } // AUTO RECOVERY for token issues if (autoRecovery && (errorMessage.includes('CSRF') || errorMessage.includes('token'))) { console.log('🚨 STARTING AUTO RECOVERY...'); // Show emergency status const statusDisplay = showEmergencyStatus('OTOMATIK KURTARMA BAŞLATILIYOR... Token yenileniyor ve debug mode deneniyor...', true); try { console.log('🔄 Auto recovery: Token refreshing...'); await refreshCSRFToken(); statusDisplay.querySelector('div:nth-child(2)').textContent = 'Token yenilendi! Debug mode ile kaydetme deneniyor...'; console.log('🔄 Auto recovery: Trying debug mode save...'); const debugResult = await saveChangesDebugMode(newConfig || currentConfig); if (debugResult) { statusDisplay.remove(); showSecurityNotification('✅ OTOMATIK KURTARMA BAŞARILI! Değişiklikler debug mode ile kaydedildi.', 'success'); return; } } catch (recoveryError) { console.error('❌ Auto recovery failed:', recoveryError); statusDisplay.remove(); showEmergencyStatus('OTOMATIK KURTARMA BAŞARISIZ! Manuel kurtarma seçenekleri gösteriliyor...'); } } // MANUAL RECOVERY OPTIONS let recoveryMessage = `🚨 CRITICAL ERROR DETECTED ❌ Hata: ${errorMessage} 🔧 RECOVERY OPTIONS:`; if (recoveryOptions.length > 0) { recoveryMessage += '\n\n' + recoveryOptions.map((option, index) => `${index + 1}. ${option}`).join('\n'); } else { recoveryMessage += '\n\n1. 🔄 Debug mode ile kaydet\n2. 🚨 Emergency cache temizle\n3. 🔄 Sayfayı yenile'; } recoveryMessage += '\n\nEADY TO PROCEED?'; if (confirm(recoveryMessage + '\n\nDebug mode ile kaydetmeyi deneyelim mi?')) { // Show manual recovery status const manualStatusDisplay = showEmergencyStatus('MANUEL KURTARMA BAŞLATILIYOR... Debug mode ile kaydetme deneniyor...', true); try { console.log('🔄 Manual recovery: Trying debug mode...'); const debugResult = await saveChangesDebugMode(newConfig || currentConfig); if (debugResult) { manualStatusDisplay.remove(); showSecurityNotification('✅ MANUEL KURTARMA BAŞARILI! Değişiklikler debug mode ile kaydedildi.', 'success'); return; } } catch (debugError) { console.error('❌ Manual debug recovery failed:', debugError); manualStatusDisplay.remove(); showEmergencyStatus('MANUEL KURTARMA DA BAŞARISIZ! Emergency cache clear öneriliyor...'); } } // LAST RESORT - Emergency cache clear if (confirm('❌ Kurtarma başarısız!\n\n🚨 Son çare olarak Emergency Cache Clear yapılsın mı?\n\nBu işlem admin panelini tamamen sıfırlayacak.')) { emergencyCacheClear(); } else { alert('❌ Kaydetme başarısız oldu.\n\nLütfen sayfayı yenileyip tekrar deneyin.\n\nSorun devam ederse teknik destek ile iletişime geçin.'); } } } // Güvenli deep clone fonksiyonu function safeDeepClone(obj) { try { return JSON.parse(JSON.stringify(obj)); } catch (error) { console.error('Deep clone error:', error); return {}; } } // Form verilerini güvenli şekilde toplama - ROBUST VERSION function collectFormData() { const formData = {}; try { console.log('🔍 ADMIN PANEL FORM COLLECTION BAŞLATILIYOR...'); // Önce admin sections var mı kontrol et const adminSections = document.getElementById('admin-sections'); console.log('📋 Admin sections element:', adminSections ? 'FOUND' : 'NOT FOUND'); let inputs; if (adminSections) { inputs = adminSections.querySelectorAll('input[name], textarea[name], select[name]'); console.log(`📝 Admin sections içinde ${inputs.length} input bulundu`); } else { // Fallback - tüm sayfa inputs inputs = document.querySelectorAll('input[name], textarea[name], select[name]'); console.log(`📝 Fallback: Sayfa genelinde ${inputs.length} input bulundu`); } if (!inputs || inputs.length === 0) { throw new Error('Hiç form input bulunamadı'); } return collectFromInputs(inputs, formData); } catch (error) { console.error('❌ Form data collection error:', error); throw new Error('Form verisi toplanamadı: ' + error.message); } } // Helper function for input collection function collectFromInputs(inputs, formData) { let processedCount = 0; let errorCount = 0; inputs.forEach((input, index) => { try { const name = input.name; if (!name || name.trim() === '') { console.debug(`Input ${index}: boş name atlandı`); return; } console.log(`🔍 Processing input ${index}: "${name}" = "${input.value}"`); // REMOVED STRICT VALIDATION - artık tüm name formatları kabul ediliyor // Admin panel'de basit name'ler de olabilir let value; try { if (input.type === 'checkbox') { value = input.checked; } else if (input.type === 'number') { const numValue = parseFloat(input.value); value = isNaN(numValue) ? 0 : numValue; } else if (input.type === 'color') { value = input.value || '#000000'; } else { value = input.value || ''; } } catch (valueError) { console.warn(`Input ${index} value error:`, valueError); value = ''; } // Array handling için özel kontroller try { if (name.includes('[') && name.includes(']')) { const arrayMatch = name.match(/(.+)\[(\d+)\]\.(.+)/); if (arrayMatch) { const [, basePath, arrayIndex, property] = arrayMatch; const keys = basePath.split('.'); const index = parseInt(arrayIndex); if (isNaN(index)) { throw new Error(`Invalid array index: ${arrayIndex}`); } keys.push(index, property); setNestedValue(formData, keys, value); processedCount++; } else { console.warn(`Invalid array format: ${name}`); } } else { const keys = name.split('.'); if (keys.length === 0) { throw new Error(`Empty keys for name: ${name}`); } setNestedValue(formData, keys, value); processedCount++; } } catch (nestError) { console.error(`Nested value error for ${name}:`, nestError); errorCount++; } } catch (error) { console.error(`Error processing input ${index} (${input.name}):`, error); errorCount++; } }); console.log(`📊 Form collection summary: ${processedCount} processed, ${errorCount} errors`); if (processedCount === 0) { throw new Error('Hiç form verisi işlenemedi'); } if (errorCount > processedCount * 0.5) { throw new Error(`Çok fazla hata: ${errorCount}/${inputs.length}`); } return formData; } // Nested değer atama - ROBUST VERSION function setNestedValue(obj, keys, value) { if (!obj || !keys || keys.length === 0) { throw new Error('Invalid parameters for setNestedValue'); } let current = obj; try { for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; const nextKey = keys[i + 1]; // Key validation if (key === null || key === undefined) { throw new Error(`Invalid key at index ${i}: ${key}`); } // Check if current is a valid object if (current === null || current === undefined) { throw new Error(`Cannot set property ${key} on null/undefined`); } // Type checking if (typeof current !== 'object') { throw new Error(`Cannot set property ${key} on non-object: ${typeof current}`); } if (!current[key]) { current[key] = typeof nextKey === 'number' ? [] : {}; } current = current[key]; } const finalKey = keys[keys.length - 1]; // Final key validation if (finalKey === null || finalKey === undefined) { throw new Error(`Invalid final key: ${finalKey}`); } // Final assignment current[finalKey] = value; } catch (error) { console.error('❌ setNestedValue error:', error); console.error('Keys:', keys); console.error('Value:', value); throw new Error(`Nested value assignment failed: ${error.message}`); } } // Config'i güvenli şekilde güncelleme function safeUpdateConfig(baseConfig, formData) { try { // Form data'yı base config'e merge et const updated = deepMerge(baseConfig, formData); // Özel temizlik işlemleri if (updated.header?.social) { updated.header.social = updated.header.social.filter(item => item && item.url && item.url.trim() !== '' ); } if (updated.footer?.payments) { updated.footer.payments = updated.footer.payments.filter(item => item && item.img && item.img.trim() !== '' ); } return updated; } catch (error) { console.error('Config update error:', error); throw new Error('Config güncellemesi başarısız'); } } // Deep merge fonksiyonu function deepMerge(target, source) { const result = { ...target }; for (const key in source) { if (source.hasOwnProperty(key)) { if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) { result[key] = deepMerge(target[key] || {}, source[key]); } else { result[key] = source[key]; } } } return result; } // Config validation function validateConfig(config) { const errors = []; try { // JSON serialization test const jsonString = JSON.stringify(config); if (jsonString.length > 5000000) { // 5MB limit errors.push('Config too large'); } // Required fields check if (!config.pageTitle) errors.push('Page title required'); if (!config.hero) errors.push('Hero section required'); return { valid: errors.length === 0, errors: errors }; } catch (error) { return { valid: false, errors: ['Config validation failed: ' + error.message] }; } } // API'ye güvenli gönderim async function safeSendToAPI(config, csrfToken) { try { console.log('📡 API Request starting...'); console.log('📊 Config size:', JSON.stringify(config).length, 'characters'); const response = await fetch('api.php', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify(config) }); console.log('📨 API Response status:', response.status); const responseText = await response.text(); console.log('📄 API Response text:', responseText.substring(0, 200)); let result; try { result = JSON.parse(responseText); } catch (parseError) { console.error('API JSON parse error:', parseError); throw new Error('API yanıtı geçersiz JSON: ' + responseText.substring(0, 100)); } if (!response.ok) { throw new Error(result.error || `HTTP ${response.status}: ${response.statusText}`); } return result; } catch (error) { console.error('API send error:', error); throw error; } } async function saveChangesDebugMode(config) { console.log('🔧 === DEBUG MODE SAVE ==='); if (!config) { alert('❌ Debug mode: Config verisi bulunamadı'); return false; } try { console.log('🚀 Debug mode: Starting save...'); console.log('📊 Config keys:', Object.keys(config)); // Debug mode'da da token yenile console.log('🔄 Debug mode: Token yenileniyor...'); await refreshCSRFToken(); const response = await fetch('api.php?debug=true', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config) }); console.log('📨 Debug response status:', response.status); const responseText = await response.text(); console.log('📄 Debug response text:', responseText.substring(0, 300)); let result; try { result = JSON.parse(responseText); } catch (parseError) { console.error('Debug JSON parse error:', parseError); throw new Error('Debug mode: API yanıtı geçersiz JSON: ' + responseText.substring(0, 100)); } if (response.ok && result.success) { console.log('✅ Debug mode başarılı!'); alert('✅ Debug mode ile kaydetme başarılı! CSRF problemi çözüldü.'); // Config'i güncelle currentConfig = config; siteConfig = config; // Public page'i güncelle renderPublicPage(config); // Cache problemini çözmek için anasayfayı yenile setTimeout(() => { console.log('🔄 Debug mode: Cache problemini önlemek için anasayfa yenileniyor...'); const newTab = window.open('index.php?t=' + Date.now(), '_blank'); if (newTab) { newTab.focus(); } else { showCacheRefreshNotification(); } }, 2000); return true; } else { throw new Error(result.error || `Debug mode HTTP ${response.status}: ${response.statusText}`); } } catch (error) { console.error('💥 Debug mode error:', error); alert('❌ Debug mode kaydetme hatası: ' + error.message); return false; } } function attachFormHandlers() { console.log('🔗 Form handlers ekleniyor...'); // Form State Restoration - Korunan verileri geri yükle restoreFormState(); // Color input synchronization const colorInputs = document.querySelectorAll('input[type="color"]'); colorInputs.forEach(input => { const name = input.getAttribute('name'); const textInput = document.querySelector(`input[name="${name}_text"]`); if (textInput) { // Color picker changes text input input.addEventListener('change', () => { textInput.value = input.value; // State'i hemen güncelle updateFormStateCache(name, input.value); }); // Text input changes color picker textInput.addEventListener('input', () => { if (/^#[0-9A-F]{6}$/i.test(textInput.value)) { input.value = textInput.value; // State'i hemen güncelle updateFormStateCache(name, textInput.value); } }); } }); // Auto-save on input changes to prevent data loss const allInputs = document.querySelectorAll('#admin-sections input, #admin-sections textarea, #admin-sections select'); allInputs.forEach(input => { if (!input.name || input.name.trim() === '') return; const eventType = input.type === 'checkbox' || input.type === 'radio' ? 'change' : 'input'; input.addEventListener(eventType, function() { // 🐦 TWITTER CREATOR IMMEDIATE UPDATE if (input.name === 'seo.twitter.creator') { console.log('🐦 Twitter creator input change detected:', input.value); updateFormStateCache(input.name, getInputValue(input)); return; } // Debounced auto-update for other fields clearTimeout(input.autoUpdateTimeout); input.autoUpdateTimeout = setTimeout(() => { updateFormStateCache(input.name, getInputValue(input)); }, 300); // 300ms delay }); }); console.log('✅ Form handlers eklendi - auto-save aktif'); } function restoreFormState() { try { console.log('🔄 Form state geri yükleniyor...'); const inputs = document.querySelectorAll('#admin-sections input, #admin-sections textarea, #admin-sections select'); let restoredCount = 0; inputs.forEach(input => { if (!input.name || input.name.trim() === '') return; let value = getNestedValue(formStateCache, input.name) || getNestedValue(currentConfig, input.name); // 🐦 TWITTER CREATOR SPECIAL RESTORE if (input.name === 'seo.twitter.creator') { console.log('🐦 Restoring Twitter creator field...'); // Try multiple sources for the value value = value || formStateCache?.seo?.twitter?.creator || currentConfig?.seo?.twitter?.creator || ''; console.log('🐦 Twitter creator restore value:', value); } if (value !== undefined && value !== null) { setInputValue(input, value); restoredCount++; if (input.name === 'seo.twitter.creator') { console.log('🐦 Twitter creator field restored with value:', value); } } }); console.log(`✅ ${restoredCount} form alanı geri yüklendi`); } catch (error) { console.error('❌ Form state geri yükleme hatası:', error); } } function getNestedValue(obj, path) { return path.split('.').reduce((current, key) => { return current && current[key] !== undefined ? current[key] : undefined; }, obj); } function setInputValue(input, value) { try { switch (input.type) { case 'checkbox': input.checked = Boolean(value); break; case 'radio': if (input.value === String(value)) { input.checked = true; } break; case 'number': case 'range': input.value = Number(value) || 0; break; default: input.value = String(value || ''); } } catch (error) { console.warn(`⚠️ Input value set error for ${input.name}:`, error); } } function getInputValue(input) { switch (input.type) { case 'checkbox': return input.checked; case 'radio': return input.checked ? input.value : undefined; case 'number': case 'range': return parseFloat(input.value) || 0; case 'color': return input.value || '#000000'; default: return input.value ? input.value.trim() : ''; } } function updateNestedValue(obj, path, value) { const pathParts = path.split('.'); let current = obj; for (let i = 0; i < pathParts.length - 1; i++) { const part = pathParts[i]; if (!current[part]) { current[part] = {}; } current = current[part]; } const finalPart = pathParts[pathParts.length - 1]; current[finalPart] = value; } function updateFormStateCache(fieldName, value) { if (value === undefined) return; try { console.log('📝 Form state update:', fieldName, '=', value); // 🐦 TWITTER CREATOR SPECIAL HANDLING if (fieldName === 'seo.twitter.creator') { console.log('🐦 Twitter creator field detected - ensuring structure...'); // Ensure seo.twitter structure exists in currentConfig if (!currentConfig.seo) { currentConfig.seo = {}; } if (!currentConfig.seo.twitter) { currentConfig.seo.twitter = {}; } // Set the value directly currentConfig.seo.twitter.creator = value; console.log('✅ Twitter creator set to:', currentConfig.seo.twitter.creator); // Also update formStateCache if (!formStateCache.seo) { formStateCache.seo = {}; } if (!formStateCache.seo.twitter) { formStateCache.seo.twitter = {}; } formStateCache.seo.twitter.creator = value; } else { // Standard processing for other fields // formStateCache'i güncelle updateNestedValue(formStateCache, fieldName, value); // currentConfig'i de güncelle - nested path için updateNestedValue(currentConfig, fieldName, value); } // Global değişkenleri de güncelle window.currentConfig = currentConfig; window.siteConfig = currentConfig; } catch (error) { console.warn(`⚠️ Form state cache update error for ${fieldName}:`, error); } } // Oyun kategorisi ekleme fonksiyonu function addGameCategory() { if (!currentConfig.gameCategories) currentConfig.gameCategories = {}; if (!currentConfig.gameCategories.cards) currentConfig.gameCategories.cards = []; const cards = currentConfig.gameCategories.cards; if (cards.length >= 6) { alert('Maksimum 6 oyun kategorisi ekleyebilirsiniz!'); return; } cards.push({ title_line1: 'YENİ', title_line2: 'KATEGORİ', background: { src: '/img/online-slot.png', alt: 'Yeni oyun kategorisi' }, button: { text: 'Hadi Hemen Oyna!', url: 'https://cutt.ly/Fw0yDcFe' } }); showSection('games'); } // Oyun kategorisi silme fonksiyonu function removeGameCategory(index) { if (confirm('Bu oyun kategorisini silmek istediğinizden emin misiniz?')) { if (!currentConfig.gameCategories) currentConfig.gameCategories = {}; if (!currentConfig.gameCategories.cards) currentConfig.gameCategories.cards = []; currentConfig.gameCategories.cards.splice(index, 1); showSection('games'); } } // Gelişmiş ayarlar buton fonksiyonları function createBackup() { if (confirm('Şu anki site ayarlarının yedeğini oluşturmak istediğinizden emin misiniz?')) { const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); if (!csrfToken) { alert('❌ Güvenlik token\'ı bulunamadı. Sayfayı yenileyin.'); return; } fetch('api.php?action=create_backup', { method: 'POST', headers: { 'X-CSRF-Token': csrfToken } }) .then(response => response.json()) .then(result => { if (result.success) { alert('✅ Yedek başarıyla oluşturuldu!'); } else { alert('❌ Yedek oluşturulamadı: ' + (result.error || 'Bilinmeyen hata')); } }) .catch(error => { console.error('Backup error:', error); alert('❌ Yedekleme sırasında hata oluştu: ' + error.message); }); } } function downloadConfig() { const configData = JSON.stringify(currentConfig, null, 2); const blob = new Blob([configData], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `kareasbet-config-${new Date().toISOString().split('T')[0]}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); alert('✅ Konfigürasyon dosyası indirildi!'); } function clearCache() { if (confirm('Site önbelleğini temizlemek istediğinizden emin misiniz? Bu işlem site performansını geçici olarak etkileyebilir.')) { const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); if (!csrfToken) { alert('❌ Güvenlik token\'ı bulunamadı. Sayfayı yenileyin.'); return; } fetch('api.php?action=clear_cache', { method: 'POST', headers: { 'X-CSRF-Token': csrfToken } }) .then(response => response.json()) .then(result => { if (result.success) { alert('✅ Önbellek başarıyla temizlendi!'); } else { alert('❌ Önbellek temizlenemedi: ' + (result.error || 'Bilinmeyen hata')); } }) .catch(error => { console.error('Cache clear error:', error); alert('❌ Önbellek temizleme sırasında hata oluştu: ' + error.message); }); } } // Footer yönetimi fonksiyonları function addFooterColumn() { if (!currentConfig.footer) currentConfig.footer = {}; if (!currentConfig.footer.columns) currentConfig.footer.columns = []; const columns = currentConfig.footer.columns; if (columns.length >= 4) { alert('Maksimum 4 footer kolonu önerilir!'); return; } columns.push({ title: 'Yeni Kolon', links: [], logos: [] }); showSection('footer'); } function removeFooterColumn(columnIndex) { if (confirm('Bu footer kolonunu silmek istediğinizden emin misiniz?')) { if (!currentConfig.footer) currentConfig.footer = {}; if (!currentConfig.footer.columns) currentConfig.footer.columns = []; currentConfig.footer.columns.splice(columnIndex, 1); showSection('footer'); } } function addFooterLink(columnIndex) { if (!currentConfig.footer) currentConfig.footer = {}; if (!currentConfig.footer.columns) currentConfig.footer.columns = []; if (!currentConfig.footer.columns[columnIndex]) return; if (!currentConfig.footer.columns[columnIndex].links) { currentConfig.footer.columns[columnIndex].links = []; } currentConfig.footer.columns[columnIndex].links.push({ text: 'Yeni Link', url: 'https://' }); showSection('footer'); } function removeFooterLink(columnIndex, linkIndex) { if (confirm('Bu linki silmek istediğinizden emin misiniz?')) { if (!currentConfig.footer?.columns?.[columnIndex]?.links) return; currentConfig.footer.columns[columnIndex].links.splice(linkIndex, 1); showSection('footer'); } } function addFooterLogo(columnIndex) { if (!currentConfig.footer) currentConfig.footer = {}; if (!currentConfig.footer.columns) currentConfig.footer.columns = []; if (!currentConfig.footer.columns[columnIndex]) return; if (!currentConfig.footer.columns[columnIndex].logos) { currentConfig.footer.columns[columnIndex].logos = []; } currentConfig.footer.columns[columnIndex].logos.push({ img: '/img/logo.png', alt: 'Logo', url: 'https://' }); showSection('footer'); } function removeFooterLogo(columnIndex, logoIndex) { if (confirm('Bu logoyu silmek istediğinizden emin misiniz?')) { if (!currentConfig.footer?.columns?.[columnIndex]?.logos) return; currentConfig.footer.columns[columnIndex].logos.splice(logoIndex, 1); showSection('footer'); } } // EMERGENCY CACHE CLEARING - Admin panel için window.emergencyCacheClear = function() { console.log('🚨 EMERGENCY CACHE CLEAR BAŞLATILDI'); if (confirm('🚨 EMERGENCY CACHE TEMIZLEME\n\nBu işlem admin panelini tamamen yeniler ve tüm cache\'i temizler.\n\nDevam edilsin mi?')) { // Local storage temizle localStorage.clear(); sessionStorage.clear(); // Cache API ile temizle (modern browsers) if ('caches' in window) { caches.keys().then(function(names) { names.forEach(function(name) { caches.delete(name); }); }); } // Service worker'ları temizle if ('serviceWorker' in navigator) { navigator.serviceWorker.getRegistrations().then(function(registrations) { for(let registration of registrations) { registration.unregister(); } }); } alert('✅ Emergency cache temizleme tamamlandı!\n\nSayfa yeniden yükleniyor...'); // Force refresh window.location.href = window.location.href + '?emergency_clear=' + Date.now(); } }; // Cache refresh notification fonksiyonu function showCacheRefreshNotification() { const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 10000; background: linear-gradient(45deg, #3B82F6, #1D4ED8); color: white; padding: 20px 30px; border-radius: 12px; font-weight: bold; box-shadow: 0 10px 25px rgba(59, 130, 246, 0.4); border: 2px solid #60A5FA; max-width: 300px; `; notification.innerHTML = `
🔄
Cache Yenileniyor
Anasayfayı kontrol etmek için
CTRL+SHIFT+R yapın veya
`; document.body.appendChild(notification); setTimeout(() => notification?.remove(), 8000); } // EMERGENCY STATUS DISPLAY function showEmergencyStatus(message, isRecovering) { if (typeof isRecovering === 'undefined') isRecovering = false; // Remove existing emergency status const existing = document.getElementById('emergency-status'); if (existing) existing.remove(); const notification = document.createElement('div'); notification.id = 'emergency-status'; notification.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; z-index: 20000; background: ${isRecovering ? 'linear-gradient(45deg, #F59E0B, #D97706)' : 'linear-gradient(45deg, #DC2626, #991B1B)'}; color: white; padding: 15px 20px; font-weight: bold; text-align: center; box-shadow: 0 4px 15px rgba(0,0,0,0.5); border-bottom: 3px solid ${isRecovering ? '#FBBF24' : '#F87171'}; `; notification.innerHTML = `
${isRecovering ? '🔄' : '🚨'}
${message}
${isRecovering ? `
` : ''}
`; document.body.appendChild(notification); if (!isRecovering) { setTimeout(() => notification?.remove(), 10000); } return notification; } // Security notification fonksiyonu function showSecurityNotification(message, type = 'info') { const notification = document.createElement('div'); let bgColor, borderColor; switch(type) { case 'success': bgColor = 'linear-gradient(45deg, #10B981, #047857)'; borderColor = '#34D399'; break; case 'warning': bgColor = 'linear-gradient(45deg, #F59E0B, #D97706)'; borderColor = '#FBBF24'; break; case 'error': bgColor = 'linear-gradient(45deg, #DC2626, #991B1B)'; borderColor = '#F87171'; break; default: bgColor = 'linear-gradient(45deg, #3B82F6, #1D4ED8)'; borderColor = '#60A5FA'; } notification.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 10000; background: ${bgColor}; color: white; padding: 15px 25px; border-radius: 10px; font-weight: bold; box-shadow: 0 10px 25px rgba(0,0,0,0.3); border: 2px solid ${borderColor}; max-width: 300px; `; notification.innerHTML = `
${message}
`; document.body.appendChild(notification); setTimeout(() => notification?.remove(), 4000); } // CSRF token yenileme fonksiyonu - GÜÇLENDIRILDI async function refreshCSRFToken() { try { console.log('🔄 Token yenileme başlatıldı...'); // Birden fazla deneme yap for (let attempt = 1; attempt <= 3; attempt++) { try { const response = await fetch('api.php?action=get_csrf_token&t=' + Date.now() + '&attempt=' + attempt, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' } }); console.log(`🔄 Token yenileme denemesi ${attempt}: HTTP ${response.status}`); if (response.ok) { const responseText = await response.text(); console.log('🔍 Token API response:', responseText.substring(0, 200)); let result; try { result = JSON.parse(responseText); } catch (parseError) { console.warn(`Deneme ${attempt}: JSON parse hatası, devam ediliyor...`); continue; } if (result.csrf_token) { const metaTag = document.querySelector('meta[name="csrf-token"]'); if (metaTag) { const oldToken = metaTag.getAttribute('content'); metaTag.setAttribute('content', result.csrf_token); console.log(`✅ CSRF token başarıyla yenilendi! (Deneme ${attempt})`); console.log('🔑 Eski token:', oldToken?.substring(0, 10) + '...'); console.log('🔑 Yeni token:', result.csrf_token.substring(0, 10) + '...'); return true; } } } // Başarısızsa biraz bekle if (attempt < 3) { await new Promise(resolve => setTimeout(resolve, 500)); } } catch (attemptError) { console.warn(`Deneme ${attempt} başarısız:`, attemptError.message); if (attempt < 3) { await new Promise(resolve => setTimeout(resolve, 500)); } } } throw new Error('3 denemede de token yenilenemedi'); } catch (error) { console.error('❌ CSRF token yenileme tamamen başarısız:', error); return false; } } async function initialize() { try { // 🛡️ CRITICAL SECURITY FIX: gameCategories.cards Array Safety - Before any operations console.log('🔧 Sistem güvenlik kontrolleri başlatılıyor...'); // Ensure gameCategories exists and cards is always an array if (!window.currentConfig) { window.currentConfig = {}; } if (!window.currentConfig.gameCategories) { console.log('🔧 gameCategories eksik - oluşturuluyor...'); window.currentConfig.gameCategories = { title_red: 'EN POPÜLER', title_white: ' OYUNLARIMIZ', sub_title: 'Hemen Oynamaya Başla!', description: 'Binlerce oyun arasından favori kategorini seç ve hemen oynamaya başla!', cards: [] }; } // CRITICAL: Ensure gameCategories.cards is ALWAYS an array if (!window.currentConfig.gameCategories.cards || !Array.isArray(window.currentConfig.gameCategories.cards)) { console.warn('⚠️ gameCategories.cards array güvenlik düzeltmesi uygulanıyor...'); window.currentConfig.gameCategories.cards = []; } console.log('✅ gameCategories.cards array güvenliği sağlandı:', Array.isArray(window.currentConfig.gameCategories.cards)); const urlParams = new URLSearchParams(window.location.search); const isAdminPage = urlParams.get('admin') === 'true'; const isLoggedIn = false; // CSRF token yenileme (sadece admin için) - GÜÇLENDIRILDI if (isAdminPage && isLoggedIn) { console.log('🔄 Admin panel başlatılıyor - Token yenileniyor...'); try { const tokenSuccess = await refreshCSRFToken(); if (tokenSuccess) { console.log('✅ Admin panel başlangıç token yenileme başarılı'); } else { console.warn('⚠️ Admin panel başlangıç token yenileme başarısız - devam ediliyor'); } } catch (tokenError) { console.error('❌ Admin panel token yenileme hatası:', tokenError); // Token refresh failed - continue anyway but warn user setTimeout(() => { alert('⚠️ Güvenlik token\'ı yenilenemedi.\n\nİlk kaydetme işleminizde sorun çıkarsa sayfayı yenileyin.'); }, 2000); } } // Config yükleme const config = await getSiteConfig(); if (!config || Object.keys(config).length === 0) { return; } // 🛡️ Post-load security fix for gameCategories.cards if (!config.gameCategories) { console.log('🔧 Post-load: gameCategories eksik - oluşturuluyor...'); config.gameCategories = { title_red: 'EN POPÜLER', title_white: ' OYUNLARIMIZ', sub_title: 'Hemen Oynamaya Başla!', description: 'Binlerce oyun arasından favori kategorini seç ve hemen oynamaya başla!', cards: [] }; } if (!config.gameCategories.cards || !Array.isArray(config.gameCategories.cards)) { console.warn('⚠️ Post-load: gameCategories.cards array değil - düzeltiliyor...'); config.gameCategories.cards = []; } console.log('✅ Post-load gameCategories.cards safety confirmed:', Array.isArray(config.gameCategories.cards)); // 🐦 TWITTER CREATOR FIX: Ensure seo.twitter structure in loaded config if (!config.seo) { config.seo = {}; } if (!config.seo.twitter) { config.seo.twitter = {}; } console.log('🐦 Twitter Creator structure ensured - current value:', config.seo.twitter.creator); // Sayfa türüne göre inizialize if (isAdminPage) { if (isLoggedIn) { console.log('🎯 Admin panel başlatılıyor...'); // Config'i set et currentConfig = config; siteConfig = config; window.currentConfig = config; window.siteConfig = config; console.log('📊 Config set for admin panel:', Object.keys(config)); // Public view'ı gizle const publicView = document.getElementById('public-view'); if (publicView) { publicView.style.display = 'none'; } // Admin paneli göster - force display const adminPanel = document.getElementById('admin-panel'); if (adminPanel) { adminPanel.style.display = 'flex'; adminPanel.style.visibility = 'visible'; adminPanel.style.opacity = '1'; console.log('✅ Admin panel display set to flex'); } else { console.error('❌ Admin panel element not found'); } // Admin paneli başlat - emergency fallback ile try { console.log('🚀 initializeAdminPanel çağrılıyor...'); await initializeAdminPanel(); console.log('✅ Admin panel başarıyla başlatıldı'); } catch (adminError) { console.error('❌ Admin panel başlatma hatası:', adminError); // Emergency fallback: Manual admin panel initialization console.log('🆘 Emergency admin panel fallback başlatılıyor...'); // Load emergency functions loadEmergencyAdminFunctions(); // Manual section build try { buildAdminSection('dashboard'); console.log('✅ Emergency admin panel başlatıldı'); // Setup manual navigation document.querySelectorAll('.admin-nav-item').forEach(item => { item.addEventListener('click', function(e) { e.preventDefault(); const section = this.getAttribute('data-section'); if (section) { console.log('📍 Switching to section:', section); showSection(section); } }); }); // Setup logout button document.querySelector('[data-action="logout"]').addEventListener('click', function() { window.location.href = 'index.php?logout=true'; }); } catch (emergencyError) { console.error('❌ Emergency fallback failed:', emergencyError); // Last resort: Show basic admin interface document.getElementById('admin-sections').innerHTML = `

⚠️ Admin Panel Yükleme Hatası

Admin paneli düzgün yüklenemedi. Aşağıdaki seçenekleri deneyin:

🐛 Debug Bilgisi:

Config loaded: ${config ? 'YES' : 'NO'}

Config sections: ${config ? Object.keys(config).join(', ') : 'NONE'}

JavaScript functions: Check browser console for errors

`; } } } else { document.getElementById('admin-login').style.display = 'flex'; } } else { // Public sayfa render et currentConfig = config; siteConfig = config; renderPublicPage(config); } } catch (error) { // System initialization error - show basic error page document.body.innerHTML = `

🚨 Sistem Hatası

Site başlatılırken bir hata oluştu.

`; } } // Test görsel ayarlama fonksiyonları function setTestLogo(type) { const testImages = { header: { src: '/img/kareaslogo.png', alt: 'Kareasbet Test Logo' }, hero: { src: '/img/kareaslogo.png', alt: 'Kareasbet Hero Test' }, background: { src: '/img/kareasbet-bannerone.jpg', alt: 'Test Background' }, gameCategories: { src: '/img/bg-tokyobet.jpg', alt: 'Game Categories Background' } }; if (!testImages[type]) return; const inputs = { header: { src: 'header.logoSrc', alt: 'header.logoAlt' }, hero: { src: 'hero.heroImage.src', alt: 'hero.heroImage.alt' }, background: { src: 'background.mainBg', alt: 'background.alt' }, gameCategories: { src: 'gameCategories.background.src', alt: 'gameCategories.background.alt' } }; const config = inputs[type]; if (config) { const srcInput = document.querySelector(`input[name="${config.src}"]`); const altInput = document.querySelector(`input[name="${config.alt}"]`); if (srcInput) { srcInput.value = testImages[type].src; // Trigger input change event to update any listeners srcInput.dispatchEvent(new Event('input', { bubbles: true })); } if (altInput) { altInput.value = testImages[type].alt; altInput.dispatchEvent(new Event('input', { bubbles: true })); } showSecurityNotification(`✅ ${type.charAt(0).toUpperCase() + type.slice(1)} test görseli ayarlandı`, 'success'); // Update current config to reflect changes if (type === 'header') { if (!currentConfig.header) currentConfig.header = {}; currentConfig.header.logoSrc = testImages[type].src; currentConfig.header.logoAlt = testImages[type].alt; } else if (type === 'hero') { if (!currentConfig.hero) currentConfig.hero = {}; if (!currentConfig.hero.heroImage) currentConfig.hero.heroImage = {}; currentConfig.hero.heroImage.src = testImages[type].src; currentConfig.hero.heroImage.alt = testImages[type].alt; } else if (type === 'background') { if (!currentConfig.background) currentConfig.background = {}; currentConfig.background.mainBg = testImages[type].src; currentConfig.background.alt = testImages[type].alt; } else if (type === 'gameCategories') { if (!currentConfig.gameCategories) currentConfig.gameCategories = {}; if (!currentConfig.gameCategories.background) currentConfig.gameCategories.background = {}; currentConfig.gameCategories.background.src = testImages[type].src; currentConfig.gameCategories.background.alt = testImages[type].alt; } // Refresh the section to show preview if (currentSection === 'visuals') { buildAdminSection('visuals'); } } } // Yeni görsel yönetim fonksiyonları function resetAllImages() { if (!confirm('⚠️ TÜM GÖRSELLERİ SIFIRLA\n\nTüm site görsellerini varsayılan değerlere döndürmek istediğinizden emin misiniz?\n\nBu işlem geri alınamaz!')) { return; } console.log('🔄 Tüm görseller varsayılan değerlere sıfırlanıyor...'); // Reset header logo const headerLogoSrc = document.querySelector('input[name="header.logoSrc"]'); const headerLogoAlt = document.querySelector('input[name="header.logoAlt"]'); if (headerLogoSrc) { headerLogoSrc.value = '/img/kareaslogo.png'; headerLogoSrc.dispatchEvent(new Event('input', { bubbles: true })); } if (headerLogoAlt) { headerLogoAlt.value = 'Kareasbet'; headerLogoAlt.dispatchEvent(new Event('input', { bubbles: true })); } // Reset hero image const heroSrc = document.querySelector('input[name="hero.heroImage.src"]'); const heroAlt = document.querySelector('input[name="hero.heroImage.alt"]'); if (heroSrc) { heroSrc.value = '/img/kareaslogo.png'; heroSrc.dispatchEvent(new Event('input', { bubbles: true })); } if (heroAlt) { heroAlt.value = 'Kareasbet Logo'; heroAlt.dispatchEvent(new Event('input', { bubbles: true })); } // Reset background const bgSrc = document.querySelector('input[name="background.mainBg"]'); const bgAlt = document.querySelector('input[name="background.alt"]'); if (bgSrc) { bgSrc.value = '/img/kareasbet-bannerone.jpg'; bgSrc.dispatchEvent(new Event('input', { bubbles: true })); } if (bgAlt) { bgAlt.value = 'Casino Background'; bgAlt.dispatchEvent(new Event('input', { bubbles: true })); } // Reset game categories background const gameBgSrc = document.querySelector('input[name="gameCategories.background.src"]'); const gameBgAlt = document.querySelector('input[name="gameCategories.background.alt"]'); if (gameBgSrc) { gameBgSrc.value = '/img/bg-tokyobet.jpg'; gameBgSrc.dispatchEvent(new Event('input', { bubbles: true })); } if (gameBgAlt) { gameBgAlt.value = 'Games Background'; gameBgAlt.dispatchEvent(new Event('input', { bubbles: true })); } // Reset about background const aboutBgSrc = document.querySelector('input[name="about.background.src"]'); const aboutBgAlt = document.querySelector('input[name="about.background.alt"]'); if (aboutBgSrc) { aboutBgSrc.value = '/img/bg-tokyobet.jpg'; aboutBgSrc.dispatchEvent(new Event('input', { bubbles: true })); } if (aboutBgAlt) { aboutBgAlt.value = 'About Background'; aboutBgAlt.dispatchEvent(new Event('input', { bubbles: true })); } // Reset SEO Open Graph image const ogImageSrc = document.querySelector('input[name="seo.openGraph.image"]'); const ogImageAlt = document.querySelector('input[name="seo.openGraph.imageAlt"]'); if (ogImageSrc) { ogImageSrc.value = '/img/kareasbet-social.jpg'; ogImageSrc.dispatchEvent(new Event('input', { bubbles: true })); } if (ogImageAlt) { ogImageAlt.value = 'Kareasbet Sosyal Medya Görseli'; ogImageAlt.dispatchEvent(new Event('input', { bubbles: true })); } // Reset mobile app image const mobileAppSrc = document.querySelector('input[name="mobileApp.image.src"]'); const mobileAppAlt = document.querySelector('input[name="mobileApp.image.alt"]'); if (mobileAppSrc) { mobileAppSrc.value = '/img/kareaslogo.png'; mobileAppSrc.dispatchEvent(new Event('input', { bubbles: true })); } if (mobileAppAlt) { mobileAppAlt.value = 'Mobil Uygulama'; mobileAppAlt.dispatchEvent(new Event('input', { bubbles: true })); } showSecurityNotification('🔄 Tüm görseller varsayılan değerlere sıfırlandı', 'warning'); // Refresh the section if (currentSection === 'visuals') { buildAdminSection('visuals'); } } function optimizeAllImages() { showSecurityNotification('⚡ Görsel optimizasyonu başlatıldı...', 'info'); // Simulate optimization process setTimeout(() => { const imageInputs = document.querySelectorAll('input[type="url"][name*="src"], input[type="url"][name*="image"]'); let optimizedCount = 0; let recommendationsCount = 0; imageInputs.forEach(input => { if (input.value && input.value.trim() !== '') { // Check for WebP format if (!input.value.includes('.webp')) { recommendationsCount++; } // Check for proper alt text const name = input.getAttribute('name'); const altName = name.replace('src', 'alt').replace('image', 'imageAlt'); const altInput = document.querySelector(`input[name="${altName}"]`); if (!altInput || !altInput.value.trim()) { recommendationsCount++; } optimizedCount++; } }); let message = `⚡ Analiz tamamlandı! ${optimizedCount} görsel tespit edildi.`; if (recommendationsCount > 0) { message += ` ${recommendationsCount} optimizasyon önerisi var (WebP formatı, alt text eksiklikleri).`; } showSecurityNotification(message, recommendationsCount > 0 ? 'warning' : 'success'); }, 2000); } function analyzeImages() { showSecurityNotification('🔍 Görsel analizi başlatılıyor...', 'info'); setTimeout(() => { // Count all image inputs const allImageInputs = document.querySelectorAll('input[type="url"][name*="src"], input[type="url"][name*="image"]'); const filledImages = Array.from(allImageInputs).filter(input => input.value && input.value.trim() !== ''); const missingImages = allImageInputs.length - filledImages.length; // Count alt text fields const altInputs = document.querySelectorAll('input[name*="alt"], input[name*="Alt"]'); const filledAlts = Array.from(altInputs).filter(input => input.value && input.value.trim() !== ''); // Calculate SEO score const seoScore = altInputs.length > 0 ? Math.round((filledAlts.length / altInputs.length) * 100) : 100; // Update display const imageCountEl = document.getElementById('image-count'); const missingCountEl = document.getElementById('missing-count'); const seoScoreEl = document.getElementById('seo-score'); if (imageCountEl) imageCountEl.textContent = filledImages.length; if (missingCountEl) missingCountEl.textContent = missingImages; if (seoScoreEl) seoScoreEl.textContent = seoScore + '%'; // Change colors based on status if (missingCountEl) { if (missingImages === 0) { missingCountEl.className = 'text-2xl font-bold text-green-400'; } else if (missingImages <= 2) { missingCountEl.className = 'text-2xl font-bold text-yellow-400'; } else { missingCountEl.className = 'text-2xl font-bold text-red-400'; } } if (seoScoreEl) { if (seoScore >= 90) { seoScoreEl.className = 'text-2xl font-bold text-green-400'; } else if (seoScore >= 70) { seoScoreEl.className = 'text-2xl font-bold text-yellow-400'; } else { seoScoreEl.className = 'text-2xl font-bold text-red-400'; } } let statusMessage = '📊 Analiz tamamlandı! '; if (missingImages === 0 && seoScore >= 90) { statusMessage += 'Tüm görseller mükemmel durumda!'; } else if (missingImages > 0) { statusMessage += `${missingImages} eksik görsel tespit edildi.`; } else if (seoScore < 70) { statusMessage += 'SEO için daha fazla alt text eklemelisiniz.'; } else { statusMessage += 'Görseller genel olarak iyi durumda.'; } showSecurityNotification(statusMessage, seoScore >= 80 && missingImages === 0 ? 'success' : 'warning'); }, 1500); } window.uploadImage = async function(fileInput, configPath) { try { console.log('📤 Görsel yükleme başlatılıyor...', configPath); if (!fileInput.files || fileInput.files.length === 0) { showSecurityNotification('❌ Lütfen bir dosya seçin', 'error'); return; } const file = fileInput.files[0]; const maxSize = 5 * 1024 * 1024; if (file.size > maxSize) { showSecurityNotification('❌ Dosya boyutu 5MB\'dan büyük olamaz', 'error'); fileInput.value = ''; return; } const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp']; if (!allowedTypes.includes(file.type)) { showSecurityNotification('❌ Sadece JPEG, PNG, GIF ve WebP dosyaları desteklenir', 'error'); fileInput.value = ''; return; } const loadingNotification = document.createElement('div'); loadingNotification.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 9999; background: linear-gradient(45deg, #3B82F6, #1D4ED8); color: white; padding: 15px 25px; border-radius: 10px; font-weight: bold; box-shadow: 0 10px 25px rgba(59, 130, 246, 0.4); border: 1px solid #60A5FA; `; loadingNotification.innerHTML = `
Görsel yükleniyor...
`; document.body.appendChild(loadingNotification); const formData = new FormData(); formData.append('image', file); console.log('📡 Görsel upload.php\'ye gönderiliyor...'); const response = await fetch('upload.php', { method: 'POST', body: formData }); const result = await response.json(); loadingNotification?.remove(); if (result.success && result.url) { console.log('✅ Görsel başarıyla yüklendi:', result.url); updateConfigPath(configPath, result.url); updateImagePreview(configPath, result.url); showSecurityNotification('✅ Görsel başarıyla yüklendi!', 'success'); const altPath = configPath.replace('.src', '.alt').replace('Src', 'Alt'); const altInput = document.querySelector(`input[name="${altPath}"]`); if (altInput && (!altInput.value || altInput.value.trim() === '')) { const defaultAlt = file.name.replace(/\.[^/.]+$/, "").replace(/[_-]/g, ' '); altInput.value = defaultAlt; updateConfigPath(altPath, defaultAlt); } if (confirm('✅ Görsel yüklendi!\n\n🔄 Değişiklikleri şimdi kaydetmek ister misiniz?\n\n(Bu işlem sitenizi hemen günceller)')) { await saveChanges(); } else { showSecurityNotification('💡 Değişiklikleri kaydetmeyi unutmayın!', 'warning'); } } else { console.error('❌ Görsel yükleme hatası:', result.error); showSecurityNotification('❌ Yükleme hatası: ' + (result.error || 'Bilinmeyen hata'), 'error'); fileInput.value = ''; // Input'u temizle } } catch (error) { console.error('❌ Upload error:', error); showSecurityNotification('❌ Yükleme hatası: ' + error.message, 'error'); document.querySelector('[style*="Görsel yükleniyor"]')?.remove(); fileInput.value = ''; } }; function updateConfigPath(path, value) { console.log('🔧 Config path güncelleniyor:', path, '=', value); if (!currentConfig) { currentConfig = {}; } const pathParts = path.split('.'); let current = currentConfig; for (let i = 0; i < pathParts.length - 1; i++) { const part = pathParts[i]; if (/^\d+$/.test(part)) { const arrayIndex = parseInt(part); if (!Array.isArray(current)) { current = []; } if (!current[arrayIndex]) { current[arrayIndex] = {}; } current = current[arrayIndex]; } else { if (!current[part]) { current[part] = {}; } current = current[part]; } } const finalPart = pathParts[pathParts.length - 1]; if (/^\d+$/.test(finalPart)) { const arrayIndex = parseInt(finalPart); if (!Array.isArray(current)) { current = []; } current[arrayIndex] = value; } else { current[finalPart] = value; } const input = document.querySelector(`input[name="${path}"]`); if (input) { input.value = value; input.dispatchEvent(new Event('input', { bubbles: true })); } console.log('✅ Config path güncellendi:', path); } function updateImagePreview(configPath, imageUrl) { console.log('🖼️ Görsel önizleme güncelleniyor:', configPath, imageUrl); // Arka plan görselleri için önizleme güncelleme if (configPath.includes('background.mainBg')) { // Ana sayfa arka planı önizleme güncelleme const bgPreview = document.querySelector('[style*="background-image"][style*="kareasbet-bannerone"], [style*="background-image"][style*="mainBg"]'); if (bgPreview) { bgPreview.style.backgroundImage = `url('${imageUrl}?t=${Date.now()}')`; console.log('✅ Ana sayfa arka plan önizlemesi güncellendi'); } // Eğer visuals bölümündeysek, bölümü yeniden yükle if (currentSection === 'visuals') { setTimeout(() => { buildAdminSection('visuals'); console.log('🔄 Visuals bölümü yeniden yüklendi - Ana sayfa arka planı'); }, 500); } return; } if (configPath.includes('gameCategories.background.src')) { // Oyun kategorileri arka planı önizleme güncelleme const gamesBgPreview = document.querySelector('[style*="background-image"][style*="bg-tokyobet"], [style*="background-image"][style*="gameCategories"]'); if (gamesBgPreview) { gamesBgPreview.style.backgroundImage = `linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url('${imageUrl}?t=${Date.now()}')`; console.log('✅ Oyun kategorileri arka plan önizlemesi güncellendi'); } // Eğer visuals bölümündeysek, bölümü yeniden yükle if (currentSection === 'visuals') { setTimeout(() => { buildAdminSection('visuals'); console.log('🔄 Visuals bölümü yeniden yüklendi - Oyun kategorileri arka planı'); }, 500); } return; } if (configPath.includes('about.background.src')) { // Hakkımızda bölümü arka planı önizleme güncelleme const aboutBgPreview = document.querySelector('[style*="background-image"][style*="about"]'); if (aboutBgPreview) { aboutBgPreview.style.backgroundImage = `linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url('${imageUrl}?t=${Date.now()}')`; console.log('✅ Hakkımızda bölümü arka plan önizlemesi güncellendi'); } // Eğer visuals bölümündeysek, bölümü yeniden yükle if (currentSection === 'visuals') { setTimeout(() => { buildAdminSection('visuals'); console.log('🔄 Visuals bölümü yeniden yüklendi - Hakkımızda arka planı'); }, 500); } return; } // Diğer görsel türleri için mevcut önizleme sistemi let previewSelector = ''; if (configPath.includes('header.logoSrc')) { previewSelector = '[data-preview="header-logo"]'; } else if (configPath.includes('hero.heroImage.src')) { previewSelector = '[data-preview="hero-image"]'; } else if (configPath.includes('mobileApp.image.src')) { previewSelector = '[data-preview="mobile-app-image"]'; } else if (configPath.includes('seo.openGraph.image')) { previewSelector = '[data-preview="og-image"]'; } else if (configPath.includes('seo.favicon.')) { if (currentSection === 'visuals') { setTimeout(() => { buildAdminSection('visuals'); console.log('🔄 Visuals bölümü yeniden yüklendi - Favicon'); }, 500); } console.log('✅ Favicon önizleme yeniden yüklendi'); return; } if (previewSelector) { const previewElement = document.querySelector(previewSelector); if (previewElement) { if (previewElement.tagName === 'IMG') { previewElement.src = imageUrl + '?t=' + Date.now(); } else { previewElement.style.backgroundImage = `url('${imageUrl}?t=${Date.now()}')`; } console.log('✅ Önizleme güncellendi:', previewSelector); } } // Tüm benzer görselleri güncelle const allImages = document.querySelectorAll('img[src*="' + imageUrl.split('/').pop() + '"]'); allImages.forEach(img => { img.src = imageUrl + '?t=' + Date.now(); }); const allBgElements = document.querySelectorAll('[style*="background-image"]'); allBgElements.forEach(el => { const currentBg = el.style.backgroundImage; if (currentBg && currentBg.includes(imageUrl.split('/').pop())) { el.style.backgroundImage = `url('${imageUrl}?t=${Date.now()}')`; } }); console.log('🖼️ Tüm görsel önizlemeleri güncellendi:', configPath); } // Enhanced Config Save System - Veri Kaybı Önleyici Sistem window.saveChanges = async function() { try { console.log('💾 Gelişmiş kaydetme sistemi başlatılıyor...'); // Step 1: Backup current config before changes const configBackup = JSON.parse(JSON.stringify(currentConfig || {})); console.log('📋 Current config backed up with sections:', Object.keys(configBackup)); // Step 2: Validate current session and config if (!currentConfig || Object.keys(currentConfig).length === 0) { console.warn('⚠️ Current config is empty, attempting to reload...'); try { const freshConfig = await getSiteConfig(); if (freshConfig && Object.keys(freshConfig).length > 0) { currentConfig = freshConfig; window.currentConfig = freshConfig; console.log('✅ Fresh config loaded with sections:', Object.keys(freshConfig)); } else { throw new Error('Fresh config is also empty'); } } catch (reloadError) { console.error('❌ Could not reload config:', reloadError); alert('❌ Yapılandırma yüklenemedi. Lütfen sayfayı yenileyin.'); return; } } // Step 3: Show progress overlay const loadingOverlay = document.createElement('div'); loadingOverlay.id = 'save-loading'; loadingOverlay.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(45deg, rgba(0,0,0,0.9), rgba(20,20,20,0.9)); z-index: 9999; display: flex; align-items: center; justify-content: center; color: white; backdrop-filter: blur(5px); `; loadingOverlay.innerHTML = `
💾
Kaydetme İşlemi
Verileriniz güvenli şekilde kaydediliyor...
Başlatılıyor...
`; document.body.appendChild(loadingOverlay); const progressBar = document.getElementById('save-progress-bar'); const statusDiv = document.getElementById('save-status'); // Step 4: Improved form data collection with deep merge support statusDiv.textContent = 'Form verileri toplanıyor...'; progressBar.style.width = '20%'; console.log('🔍 Form verilerini toplama başlangıcı...'); const formData = {}; const inputs = document.querySelectorAll('#admin-sections input, #admin-sections textarea, #admin-sections select'); console.log(`📝 ${inputs.length} form elementi bulundu`); // Enhanced input processing with type safety inputs.forEach((input, index) => { if (!input.name || input.name.trim() === '') return; let value; const inputType = input.type; const inputName = input.name; try { // Type-safe value extraction switch (inputType) { case 'checkbox': value = input.checked; break; case 'number': case 'range': const numValue = parseFloat(input.value); value = isNaN(numValue) ? 0 : numValue; break; case 'color': value = input.value || '#000000'; break; case 'radio': if (input.checked) { value = input.value; } else { return; // Skip unchecked radio buttons } break; default: value = input.value ? input.value.trim() : ''; } // Build nested object structure with array support const pathParts = inputName.split('.'); let current = formData; for (let i = 0; i < pathParts.length - 1; i++) { const part = pathParts[i]; // Handle array indices if (/^\d+$/.test(part)) { const arrayIndex = parseInt(part); if (!Array.isArray(current)) { current = []; } if (!current[arrayIndex]) { current[arrayIndex] = {}; } current = current[arrayIndex]; } else { if (!current[part]) { current[part] = {}; } current = current[part]; } } const finalPart = pathParts[pathParts.length - 1]; if (/^\d+$/.test(finalPart)) { const arrayIndex = parseInt(finalPart); if (!Array.isArray(current)) { current = []; } current[arrayIndex] = value; } else { current[finalPart] = value; } console.log(`✅ Processed: ${inputName} = ${typeof value === 'object' ? JSON.stringify(value) : value}`); } catch (error) { console.warn(`⚠️ Error processing input ${inputName}:`, error); } }); // Step 5: Smart config merging to prevent data loss statusDiv.textContent = 'Veriler birleştiriliyor...'; progressBar.style.width = '40%'; console.log('🔄 Smart config merge başlatılıyor...'); console.log('📊 Form data sections:', Object.keys(formData)); console.log('📊 Current config sections:', Object.keys(currentConfig)); // Deep merge function to preserve existing data function deepMerge(target, source) { const result = JSON.parse(JSON.stringify(target)); // Clone target for (const key in source) { if (source[key] !== null && source[key] !== undefined) { if (typeof source[key] === 'object' && !Array.isArray(source[key]) && typeof result[key] === 'object' && !Array.isArray(result[key])) { // Recursively merge objects result[key] = deepMerge(result[key] || {}, source[key]); } else { // Direct assignment for primitives and arrays result[key] = source[key]; } } } return result; } // Create final configuration const finalConfig = deepMerge(currentConfig, formData); console.log('📋 Final config sections:', Object.keys(finalConfig)); console.log('💾 Final config size:', JSON.stringify(finalConfig).length, 'characters'); // Step 6: Validation before save statusDiv.textContent = 'Veriler doğrulanıyor...'; progressBar.style.width = '60%'; // Essential sections check const essentialSections = ['header', 'hero', 'footer', 'design']; const missingSections = essentialSections.filter(section => !finalConfig[section]); if (missingSections.length > 0) { console.warn('⚠️ Missing essential sections:', missingSections); // Restore from backup missingSections.forEach(section => { if (configBackup[section]) { finalConfig[section] = configBackup[section]; console.log(`🔄 Restored ${section} from backup`); } }); } // Step 7: API save with enhanced error handling statusDiv.textContent = 'Sunucuya gönderiliyor...'; progressBar.style.width = '80%'; const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); if (!csrfToken) { throw new Error('CSRF token bulunamadı - Güvenlik hatası'); } console.log('📡 API save başlatılıyor...'); const response = await fetch('api.php', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken, 'X-Security-Level': 'admin', 'X-Request-Time': Date.now().toString() }, body: JSON.stringify(finalConfig) }); let result; try { result = await response.json(); } catch (jsonError) { console.error('❌ JSON parse error:', jsonError); throw new Error('Sunucu yanıtı geçersiz - Lütfen tekrar deneyin'); } if (!response.ok) { console.error('❌ HTTP error:', response.status, result); throw new Error(result.error || `HTTP Hatası ${response.status}`); } // Step 8: Success handling statusDiv.textContent = 'Tamamlanıyor...'; progressBar.style.width = '100%'; // Update global config currentConfig = finalConfig; window.currentConfig = finalConfig; window.siteConfig = finalConfig; console.log('✅ Config saved successfully'); console.log('🔄 Updating page display...'); // Update public page display if not in admin mode setTimeout(() => { if (typeof renderPublicPage === 'function') { renderPublicPage(finalConfig); } }, 500); // Show success message setTimeout(() => { loadingOverlay?.remove(); // Success notification const successNotification = document.createElement('div'); successNotification.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 9999; background: linear-gradient(135deg, #10B981, #047857); color: white; padding: 20px 30px; border-radius: 10px; font-weight: bold; box-shadow: 0 10px 25px rgba(16, 185, 129, 0.4); border: 1px solid #34D399; `; successNotification.innerHTML = `
Başarıyla Kaydedildi!
Tüm değişiklikler uygulandı
`; document.body.appendChild(successNotification); setTimeout(() => successNotification?.remove(), 4000); }, 1000); } catch (error) { console.error('❌ Save error:', error); // Remove loading overlay document.getElementById('save-loading')?.remove(); // Show error notification const errorNotification = document.createElement('div'); errorNotification.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 9999; background: linear-gradient(45deg, #DC2626, #991B1B); color: white; padding: 20px 30px; border-radius: 10px; font-weight: bold; box-shadow: 0 10px 25px rgba(220, 38, 38, 0.4); border: 1px solid #F87171; `; errorNotification.innerHTML = `
Kaydetme Hatası
${error.message}
`; document.body.appendChild(errorNotification); setTimeout(() => errorNotification?.remove(), 6000); } }; initialize(); }); -->
🗨️
İletişime Geç!