/**
* 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 += `';
});
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 = `
`;
}
/**
* 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}
`;
}
/**
* 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.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}
`;
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 `
`;
}
if (hasScheduleSpeaker(session) && speakerImage) {
return `
`;
}
return `
${title}
${description ? `
${description}
` : ''}
`;
}