document.addEventListener('DOMContentLoaded', () => {
window.App = { reportCode: null, fightId: null, fightStart: 0, fightEnd: 0, phases: [], fights: [] };
const form = document.getElementById('report-form');
const output = document.getElementById('output');
const outputCard = document.getElementById('output-card');
const initialHint = document.getElementById('initial-hint');
const fightSelectCard = document.getElementById('fight-select-card');
const fightSelect = document.getElementById('fight-select');
const explorerCard = document.getElementById('event-explorer-card');
const exLoadBtn = document.getElementById('ex-load-btn');
const exAbilitySelect = document.getElementById('ex-ability');
const exPlayerSelect = document.getElementById('ex-player-name');
let allFights = [];
const codeInput = form.elements['report_code'];
codeInput.addEventListener('input', () => {
const match = codeInput.value.match(/fflogs\.com\/reports\/([A-Za-z0-9]+)/);
if (match) codeInput.value = match[1];
});
function formatDuration(ms) {
const min = Math.floor(ms / 60000);
const sec = String(Math.floor((ms % 60000) / 1000)).padStart(2, '0');
return `${min}:${sec}`;
}
function formatBossHp(fight) {
if (fight.kill) return 'Kill';
const pct = fight.fightPercentage;
if (pct == null) return '?';
return pct.toFixed(2) + '%';
}
function displayFight(fight) {
output.textContent = JSON.stringify(fight, null, 2);
outputCard.style.display = 'block';
}
fightSelect.addEventListener('change', () => {
if (!fightSelect.value) return;
const id = parseInt(fightSelect.value, 10);
const fight = allFights.find(f => f.id === id);
if (!fight) return;
window.App.fightId = id;
window.App.fightStart = fight.startTime;
window.App.fightEnd = fight.endTime;
window.App.phases = buildPhases(fight);
displayFight(fight);
explorerCard.style.display = 'block';
window.analysisTab?.onFightSelected?.();
loadAbilities(id, fight.startTime, fight.endTime);
});
function buildPhases(fight) {
const transitions = fight.phaseTransitions ?? [];
if (transitions.length === 0) return [];
const phases = transitions.map((t, i) => ({
id: t.id,
name: `Phase ${t.id}`,
startTime: t.startTime,
endTime: transitions[i + 1]?.startTime ?? fight.endTime,
}));
return [{ id: 0, name: 'Ganzer Fight', startTime: fight.startTime, endTime: fight.endTime }, ...phases];
}
async function loadAbilities(fightId, startTime, endTime) {
exAbilitySelect.innerHTML = '';
try {
const res = await fetch('api/abilities.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
report_code: window.App.reportCode,
fight_id: fightId,
start_time: startTime,
end_time: endTime,
}),
});
const json = await res.json();
exAbilitySelect.innerHTML = '';
(json.abilities ?? []).forEach(ab => {
const opt = document.createElement('option');
opt.value = ab.id;
opt.textContent = ab.name;
exAbilitySelect.appendChild(opt);
});
exPlayerSelect.innerHTML = '';
(json.players ?? []).forEach(p => {
const opt = document.createElement('option');
opt.value = p.name;
opt.textContent = p.name;
exPlayerSelect.appendChild(opt);
});
} catch {
exAbilitySelect.innerHTML = '';
}
}
exLoadBtn.addEventListener('click', async () => {
if (!window.App.fightId) return;
output.textContent = '// loading events...';
outputCard.style.display = 'block';
const params = {
report_code: window.App.reportCode,
fight_id: window.App.fightId,
start_time: window.App.fightStart,
end_time: window.App.fightEnd,
data_type: document.getElementById('ex-data-type').value,
ability_id: exAbilitySelect.value,
event_type: document.getElementById('ex-event-type').value.trim(),
player_name: document.getElementById('ex-player-name').value.trim(),
limit: document.getElementById('ex-limit').value,
start_offset: document.getElementById('ex-start-offset').value,
end_offset: document.getElementById('ex-end-offset').value,
};
try {
const res = await fetch('api/debug-events.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams(params),
});
const json = await res.json();
if (json.reauth) { window.location.href = 'auth/start.php'; return; }
output.textContent = JSON.stringify(json, null, 2);
} catch (err) {
output.textContent = '// Fehler: ' + err.message;
}
});
form.addEventListener('submit', async (e) => {
e.preventDefault();
initialHint.style.display = 'none';
outputCard.style.display = 'block';
output.textContent = '// fetching...';
fightSelectCard.style.display = 'none';
explorerCard.style.display = 'none';
fightSelect.innerHTML = '';
allFights = [];
const reportCode = form.elements['report_code'].value.trim();
window.App.reportCode = reportCode;
window.App.fightId = null;
window.App.fightStart = 0;
window.App.fightEnd = 0;
window.App.phases = [];
window.App.fights = [];
window.analysisTab?.reset?.();
let response, json;
try {
response = await fetch('api/fight.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ report_code: reportCode }),
});
json = await response.json();
} catch (err) {
output.textContent = '// network error: ' + err.message;
return;
}
if (json.reauth) {
output.textContent = '// session expired — redirecting...';
setTimeout(() => { window.location.href = 'auth/start.php'; }, 1500);
return;
}
if (json.errors) {
output.textContent = '// GraphQL error:\n' + JSON.stringify(json.errors, null, 2);
return;
}
const report = json?.data?.reportData?.report;
if (!report) {
output.textContent = JSON.stringify(json, null, 2);
return;
}
allFights = report.fights ?? [];
if (allFights.length === 0) {
output.textContent = '// Keine Fights in diesem Report gefunden.';
return;
}
allFights.forEach(fight => {
const duration = formatDuration(fight.endTime - fight.startTime);
const hp = formatBossHp(fight);
const opt = document.createElement('option');
opt.value = fight.id;
opt.textContent = `${fight.name} — ${duration} — ${hp}`;
fightSelect.appendChild(opt);
});
window.App.fights = allFights;
fightSelectCard.style.display = 'block';
output.textContent = '// Fight auswählen ↑';
window.analysisTab?.onFightsLoaded?.(allFights);
});
});