/** * DevOpsDays Istanbul - Data Loader * Bu dosya speakers.yaml ve organizers.yaml dosyalarını okuyup * HTML'e render eder. */ // YAML dosyalarını yükle ve render et document.addEventListener('DOMContentLoaded', function() { loadSpeakers(); loadOrganizers(); loadSchedule(); loadSponsors(); }); /** * Resolve image path: if only a filename is given, prepend /images/speakers/ */ function resolveImagePath(image) { if (!image) return '/images/speakers/blank-speaker.png'; if (image.startsWith('/') || image.startsWith('http')) return image; return `/images/speakers/${image}`; } /** * Resolve sponsor image path: if only a filename is given, prepend /images/sponsors/ */ function resolveSponsorImagePath(image) { if (!image) return ''; if (image.startsWith('/') || image.startsWith('http')) return image; return `/images/sponsors/${image}`; } async function loadSponsors() { try { const response = await fetch('data/sponsors.yaml'); const yamlText = await response.text(); const data = jsyaml.load(yamlText); if (data.enabled === false) { renderComingSoon('sponsors-coming-soon', 'Sponsors will be announced soon. Stay tuned!'); return; } const tiers = (data.tiers || []).filter(t => t.enabled !== false); const mediaTiers = tiers.filter(t => t.type === 'media'); const regularTiers = tiers.filter(t => t.type !== 'media'); renderSponsors(mediaTiers, 'sponsors-media'); if (mediaTiers.length > 0 && regularTiers.length > 0) { const divider = document.getElementById('sponsors-media-divider'); if (divider) divider.style.display = ''; } renderSponsors(regularTiers, 'sponsors-container'); } catch (error) { console.error('Sponsors yüklenirken hata oluştu:', error); } } function renderSponsors(tiers, containerId) { const container = document.getElementById(containerId); if (!container) return; let html = ''; tiers.forEach((tier, index) => { const width = tier.width; const typeClass = tier.type ? ` sponsors-tier-strip--${tier.type}` : ''; if (index > 0) { html += `

`; } html += `

${tier.name}

`; (tier.sponsors || []).forEach(sponsor => { const image = resolveSponsorImagePath(sponsor.image); html += `
`; }); html += '
'; }); container.innerHTML = html; } /** * "Coming Soon" placeholder mesajını ilgili container'a render et */ function renderComingSoon(containerId, message) { const container = document.getElementById(containerId); if (!container) return; container.innerHTML = `

${message}

`; } /** * Magnific Popup'ı tüm speaker kartları için başlat */ function initPopups() { if (typeof $ !== 'undefined' && typeof $.fn.magnificPopup !== 'undefined') { $('.ts-image-popup').magnificPopup({ type: 'inline', fixedContentPos: true, fixedBgPos: true, closeBtnInside: true, preloader: false, midClick: true, removalDelay: 300, mainClass: 'mfp-fade' }); } } /** * Speakers verilerini yükle ve render et */ async function loadSpeakers() { try { const response = await fetch('data/speakers.yaml'); const yamlText = await response.text(); const data = jsyaml.load(yamlText); if (data.enabled === false) { renderComingSoon('speakers-coming-soon', 'Speakers will be announced soon. Stay tuned!'); return; } const allSpeakers = data.speakers || []; // Type'a göre ayır const keynotes = allSpeakers.filter(s => s.type === 'keynote'); const regulars = allSpeakers.filter(s => s.type === 'speaker'); const ignites = allSpeakers.filter(s => s.type === 'ignite'); renderKeynoteSpeakers(keynotes); renderSpeakers(regulars, ignites); } catch (error) { console.error('Speakers yüklenirken hata oluştu:', error); } } /** * Organizers verilerini yükle ve render et */ async function loadOrganizers() { try { const response = await fetch('data/organizers.yaml'); const yamlText = await response.text(); const data = jsyaml.load(yamlText); renderOrganizers(data.organizers || []); } catch (error) { console.error('Organizers yüklenirken hata oluştu:', error); } } /** * Keynote Speakers HTML oluştur */ function renderKeynoteSpeakers(speakers) { const container = document.getElementById('keynote-speakers-container'); if (!container) return; let html = ''; speakers.forEach((speaker, index) => { html += createSpeakerCard(speaker, `keynote_${index}`); }); container.innerHTML = html; // Popup'ları başlat setTimeout(initPopups, 100); } /** * Regular ve Ignite Speakers HTML oluştur */ function renderSpeakers(speakers, igniteSpeakers) { const container = document.getElementById('speakers-container'); if (!container) return; // Tüm speaker'ları birleştir const allSpeakers = [...speakers, ...igniteSpeakers]; let html = ''; allSpeakers.forEach((speaker, index) => { html += createSpeakerCard(speaker, `speaker_${index}`); }); container.innerHTML = html; // Popup'ları başlat setTimeout(initPopups, 100); } /** * Speaker kartı HTML'i oluştur */ function createSpeakerCard(speaker, uniqueId) { const popupId = `popup_${uniqueId}`; const speakerImage = resolveImagePath(speaker.image); const companyText = speaker.company ? `@${speaker.company}` : ''; const isIgnite = speaker.type === 'ignite'; const isKeynote = speaker.type === 'keynote'; // Designation let designation = 'Speaker'; if (isKeynote) designation = 'Keynote Speaker'; else if (isIgnite) designation = `${speaker.title}${speaker.company ? ' @' + speaker.company : ''}`; // Social links HTML let socialHtml = ''; if (speaker.social) { if (speaker.social.linkedin) { socialHtml += ``; } if (speaker.social.twitter) { socialHtml += ``; } if (speaker.social.other) { const icon = speaker.social.other_icon || 'fa-globe'; socialHtml += ``; } } // Ignite session info HTML let igniteHtml = ''; if (isIgnite) { igniteHtml = `

⚡ Ignite Talk (5 minutes)

${speaker.session_name || ''}
`; } // Session name HTML (for regular speakers) let sessionHtml = ''; if (speaker.session_name && !isIgnite) { sessionHtml = `

${speaker.session_name}

`; } // Bio HTML - handle multiline const bioText = (speaker.bio || '').replace(/\n/g, '
'); return `

${speaker.name}

${speaker.title} ${companyText}

${speaker.name}

${speaker.name}

${designation} ${igniteHtml} ${sessionHtml}

${bioText}

${socialHtml ? `
${socialHtml}
` : ''}
`; } /** * Organizers HTML oluştur */ function renderOrganizers(organizers) { const container = document.getElementById('organizers-container'); if (!container) return; let html = ''; organizers.forEach(organizer => { html += createOrganizerCard(organizer); }); container.innerHTML = html; } /** * Organizer kartı HTML'i oluştur */ function createOrganizerCard(organizer) { const organizerImage = resolveImagePath(organizer.image); const companyText = organizer.company ? `@${organizer.company}` : ''; return `
${organizer.name}

${organizer.name}

${organizer.title} ${companyText}

`; } // Global speaker listesi (schedule için) let speakersData = []; /** * Schedule verilerini yükle ve render et */ async function loadSchedule() { try { // Önce speakers'ı yükle (fotoğraflar için) const speakersResponse = await fetch('data/speakers.yaml'); const speakersYaml = await speakersResponse.text(); const speakersObj = jsyaml.load(speakersYaml); speakersData = speakersObj.speakers || []; // Sonra schedule'ı yükle const response = await fetch('data/schedule.yaml'); const yamlText = await response.text(); const data = jsyaml.load(yamlText); if (data.enabled === false) { document.getElementById('schedule-full-content').style.display = 'none'; document.getElementById('schedule-coming-soon-wrapper').style.display = ''; renderComingSoon('schedule-coming-soon', 'Schedule will be announced soon. Stay tuned!'); return; } document.getElementById('schedule-coming-soon-wrapper').style.display = 'none'; document.getElementById('schedule-full-content').style.display = ''; renderSchedule(data.tracks || []); } catch (error) { console.error('Schedule yüklenirken hata oluştu:', error); } } /** * Speaker adından fotoğraf URL'i bul */ function getSpeakerImage(speakerName) { const speaker = speakersData.find(s => s.name === speakerName); return speaker ? resolveImagePath(speaker.image) : null; } /** * Speaker adından popup ID'sini bul */ function getSpeakerPopupId(speakerName) { const allSpeakers = speakersData; const keynotes = allSpeakers.filter(s => s.type === 'keynote'); const regulars = allSpeakers.filter(s => s.type === 'speaker'); const ignites = allSpeakers.filter(s => s.type === 'ignite'); // Keynote'larda ara const keynoteIndex = keynotes.findIndex(s => s.name === speakerName); if (keynoteIndex !== -1) return `popup_keynote_${keynoteIndex}`; // Regular speaker'larda ara const regularIndex = regulars.findIndex(s => s.name === speakerName); if (regularIndex !== -1) return `popup_speaker_${regularIndex}`; // Ignite speaker'larda ara const igniteIndex = ignites.findIndex(s => s.name === speakerName); if (igniteIndex !== -1) return `popup_speaker_${regulars.length + igniteIndex}`; return null; } /** * Schedule HTML oluştur */ function renderSchedule(tracks) { // Mobile schedule const mobileContainer = document.getElementById('schedule-mobile-container'); if (mobileContainer) { mobileContainer.innerHTML = renderMobileSchedule(tracks); } // Desktop schedule const desktopContainer = document.getElementById('schedule-desktop-container'); if (desktopContainer) { desktopContainer.innerHTML = renderDesktopSchedule(tracks); } // Schedule'daki popup linklerini aktif et setTimeout(initPopups, 200); } /** * İki dil/track paralel yürür: yalnızca type "Track Sessions" olan satırlar. * Diğer tüm slotlar (kayıt, keynote, mola, ignite vb.) her iki track için ortaktır. */ function isParallelTrackSession(session) { return session.type === 'Track Sessions'; } /** * Mobile schedule HTML */ function renderMobileSchedule(tracks) { let html = ''; // Track 1'de track-özel olmayan (ortak) session'lar — Track 2 sekmesinde de listelenir const sharedSessions = tracks[0].sessions.filter(s => !isParallelTrackSession(s)); tracks.forEach((track, index) => { const isActive = index === 0 ? 'show active' : ''; const trackId = `track${index + 1}`; html += `
`; if (index === 0) { // Track 1: Tüm session'lar zaten mevcut track.sessions.forEach(session => { html += createScheduleItem(session); }); } else { // Track 2: Shared session'ları ve track'e özel session'ları birleştir const allSessions = []; // Ortak program satırları: Track 2 sekmesinde ana salon (Main Stage) — paralel Türkçe oda değil sharedSessions.forEach(s => { allSessions.push({ ...s, isMainStage: true }); }); // Track 2'ye özel session'ları ekle track.sessions.forEach(s => { allSessions.push(s); }); // Saate göre sırala (numerik karşılaştırma) allSessions.sort((a, b) => { const timeA = a.time.split(' - ')[0]; const timeB = b.time.split(' - ')[0]; // "8:15" -> 8*60+15 = 495 dakika const [hoursA, minsA] = timeA.split(':').map(Number); const [hoursB, minsB] = timeB.split(':').map(Number); return (hoursA * 60 + minsA) - (hoursB * 60 + minsB); }); allSessions.forEach(session => { html += createScheduleItem(session); }); } html += '
'; }); return html; } /** * Oturum başlığı: boş speaker + eksik title durumunda "undefined" üretmez */ function getSessionTitle(session) { const speaker = session.speaker != null ? String(session.speaker).trim() : ''; if (speaker) return speaker; const title = session.title != null ? String(session.title).trim() : ''; if (title) return title; const type = session.type != null ? String(session.type).trim() : ''; if (type) return type; return 'Session'; } function hasScheduleSpeaker(session) { return session.speaker != null && String(session.speaker).trim() !== ''; } /** * Desktop schedule HTML (yan yana görünüm) */ function renderDesktopSchedule(tracks) { if (tracks.length < 2) return ''; const track1 = tracks[0]; const track2 = tracks[1]; // Track 2 session'larını time'a göre map'le (hızlı erişim için) const track2ByTime = {}; track2.sessions.forEach(session => { track2ByTime[session.time] = session; }); let html = `
Time

Track 1 (English)

Track 2 (Turkish)

`; // Track 1'deki tüm session'ları işle for (let i = 0; i < track1.sessions.length; i++) { const session1 = track1.sessions[i]; const session2 = track2ByTime[session1.time]; // Aynı saatte Track 2 session'ı var mı? html += `
${session1.time} ${session1.type === 'Ignite Talks' ? 'Ignite' : ''}
`; if (!isParallelTrackSession(session1)) { // Ortak program: tek geniş hücre (Track 1 / 2 ayrımı yok) html += createDesktopSlotInfo(session1, false); } else { // Paralel track oturumları — yan yana iki sütun html += createDesktopSlotInfo(session1, false); if (session2) { html += createDesktopSlotInfo(session2, false); } else { html += ``; } } html += `
`; } return html; } /** * Ignite speaker'ları speakers.yaml'dan al */ function getIgniteSpeakersForSchedule() { return speakersData .filter(s => s.type === 'ignite') .map(s => ({ name: s.name, talk: s.session_name })); } /** * Tek bir schedule item HTML'i (mobile) */ function createScheduleItem(session) { const title = getSessionTitle(session); let description = session.description || ''; // Note varsa ekle if (session.note) { description += ` ${session.note}`; } // Main Stage notu ekle (Track 2'de shared session'lar için) if (session.isMainStage) { description += description ? ' ' : ''; description += '(Main Stage)'; } // Ignite talks için - speakers.yaml'dan otomatik çek if (session.type === 'Ignite Talks') { const igniteSpeakers = getIgniteSpeakersForSchedule(); description = igniteSpeakers .map(s => `${s.name} — ${s.talk}`) .join('
'); if (session.isMainStage) { description += '
(Main Stage)'; } } // Speaker varsa tıklanabilir yap const popupId = hasScheduleSpeaker(session) ? getSpeakerPopupId(session.speaker) : null; const titleHtml = popupId ? `

${title}

` : `

${title}

`; return `
${session.time} ${session.type}
${titleHtml}

${description}

`; } /** * Desktop slot info HTML */ function createDesktopSlotInfo(session, isShared = false) { const title = getSessionTitle(session); let description = session.description || ''; const sharedClass = isShared ? ' shared-slot' : ''; // Note varsa ekle if (session.note) { description += ` ${session.note}`; } // Ignite talks için - speakers.yaml'dan otomatik çek if (session.type === 'Ignite Talks') { const igniteSpeakers = getIgniteSpeakersForSchedule(); return `
${igniteSpeakers.map(s => `

${s.name} - ${s.talk}

` ).join('')}
`; } // Speaker varsa fotoğraf göster ve tıklanabilir yap const speakerImage = hasScheduleSpeaker(session) ? getSpeakerImage(session.speaker) : null; const popupId = hasScheduleSpeaker(session) ? getSpeakerPopupId(session.speaker) : null; if (hasScheduleSpeaker(session) && speakerImage && popupId) { return `
${session.speaker}

${title}

${description}

`; } if (hasScheduleSpeaker(session) && speakerImage) { return `
${session.speaker}

${title}

${description}

`; } return `

${title}

${description ? `

${description}

` : ''}
`; }