Merge pull request 'akus_schabanack' (#1) from akus_schabanack into main
Reviewed-on: #1
This commit is contained in:
commit
5f0bdb3504
@ -13,19 +13,32 @@ $reportCode = preg_replace('/[^a-zA-Z0-9]/', '', $_POST['report_code'] ?? '');
|
|||||||
$fightId = (int)($_POST['fight_id'] ?? 0);
|
$fightId = (int)($_POST['fight_id'] ?? 0);
|
||||||
$startTime = (float)($_POST['start_time'] ?? 0);
|
$startTime = (float)($_POST['start_time'] ?? 0);
|
||||||
$endTime = (float)($_POST['end_time'] ?? 0);
|
$endTime = (float)($_POST['end_time'] ?? 0);
|
||||||
|
$language = strtolower(trim($_POST['language'] ?? 'en'));
|
||||||
|
$language = in_array($language, ['en', 'de', 'fr', 'jp'], true) ? $language : 'en';
|
||||||
|
$translate = 'true';
|
||||||
|
|
||||||
if (!$reportCode || !$fightId || !$endTime) { http_response_code(400); echo json_encode(['error' => 'Missing params']); exit; }
|
if (!$reportCode || !$fightId || !$endTime) { http_response_code(400); echo json_encode(['error' => 'Missing params']); exit; }
|
||||||
|
|
||||||
$token = $_SESSION['access_token'];
|
$token = $_SESSION['access_token'];
|
||||||
|
|
||||||
|
function localized_graphql_uri(string $language): string {
|
||||||
|
$host = [
|
||||||
|
'de' => 'de.fflogs.com',
|
||||||
|
'fr' => 'fr.fflogs.com',
|
||||||
|
'jp' => 'ja.fflogs.com',
|
||||||
|
][$language] ?? 'www.fflogs.com';
|
||||||
|
return preg_replace('#https://[^/]+#', 'https://' . $host, GRAPHQL_URI);
|
||||||
|
}
|
||||||
|
|
||||||
function ab_gql(string $query): array {
|
function ab_gql(string $query): array {
|
||||||
global $token;
|
global $token, $language;
|
||||||
$ch = curl_init(GRAPHQL_URI);
|
$acceptLanguage = $language === 'jp' ? 'ja' : $language;
|
||||||
|
$ch = curl_init(localized_graphql_uri($language));
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_POST => true,
|
CURLOPT_POST => true,
|
||||||
CURLOPT_POSTFIELDS => json_encode(['query' => $query]),
|
CURLOPT_POSTFIELDS => json_encode(['query' => $query]),
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $token],
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $token, 'Accept-Language: ' . $acceptLanguage],
|
||||||
CURLOPT_SSL_VERIFYPEER => !DEV_MODE,
|
CURLOPT_SSL_VERIFYPEER => !DEV_MODE,
|
||||||
]);
|
]);
|
||||||
$body = curl_exec($ch);
|
$body = curl_exec($ch);
|
||||||
@ -39,7 +52,7 @@ $mdResult = ab_gql(<<<GQL
|
|||||||
reportData {
|
reportData {
|
||||||
report(code: "$reportCode") {
|
report(code: "$reportCode") {
|
||||||
playerDetails(fightIDs: [$fightId])
|
playerDetails(fightIDs: [$fightId])
|
||||||
masterData {
|
masterData(translate: $translate) {
|
||||||
abilities { gameID name }
|
abilities { gameID name }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,9 @@ $reportCode = preg_replace('/[^a-zA-Z0-9]/', '', $_POST['report_code'] ?? '');
|
|||||||
$fightId = (int)($_POST['fight_id'] ?? 0);
|
$fightId = (int)($_POST['fight_id'] ?? 0);
|
||||||
$startTime = (float)($_POST['start_time'] ?? 0);
|
$startTime = (float)($_POST['start_time'] ?? 0);
|
||||||
$endTime = (float)($_POST['end_time'] ?? 0);
|
$endTime = (float)($_POST['end_time'] ?? 0);
|
||||||
|
$language = strtolower(trim($_POST['language'] ?? 'en'));
|
||||||
|
$language = in_array($language, ['en', 'de', 'fr', 'jp'], true) ? $language : 'en';
|
||||||
|
$translate = 'true';
|
||||||
|
|
||||||
if (!$reportCode || !$fightId || !$endTime) {
|
if (!$reportCode || !$fightId || !$endTime) {
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
@ -33,9 +36,19 @@ if (!$reportCode || !$fightId || !$endTime) {
|
|||||||
|
|
||||||
$token = $_SESSION['access_token'];
|
$token = $_SESSION['access_token'];
|
||||||
|
|
||||||
|
function localized_graphql_uri(string $language): string {
|
||||||
|
$host = [
|
||||||
|
'de' => 'de.fflogs.com',
|
||||||
|
'fr' => 'fr.fflogs.com',
|
||||||
|
'jp' => 'ja.fflogs.com',
|
||||||
|
][$language] ?? 'www.fflogs.com';
|
||||||
|
return preg_replace('#https://[^/]+#', 'https://' . $host, GRAPHQL_URI);
|
||||||
|
}
|
||||||
|
|
||||||
function fflogs_gql(string $query): array {
|
function fflogs_gql(string $query): array {
|
||||||
global $token;
|
global $token, $language;
|
||||||
$ch = curl_init(GRAPHQL_URI);
|
$acceptLanguage = $language === 'jp' ? 'ja' : $language;
|
||||||
|
$ch = curl_init(localized_graphql_uri($language));
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_POST => true,
|
CURLOPT_POST => true,
|
||||||
CURLOPT_POSTFIELDS => json_encode(['query' => $query]),
|
CURLOPT_POSTFIELDS => json_encode(['query' => $query]),
|
||||||
@ -43,6 +56,7 @@ function fflogs_gql(string $query): array {
|
|||||||
CURLOPT_HTTPHEADER => [
|
CURLOPT_HTTPHEADER => [
|
||||||
'Content-Type: application/json',
|
'Content-Type: application/json',
|
||||||
'Authorization: Bearer ' . $token,
|
'Authorization: Bearer ' . $token,
|
||||||
|
'Accept-Language: ' . $acceptLanguage,
|
||||||
],
|
],
|
||||||
CURLOPT_SSL_VERIFYPEER => !DEV_MODE,
|
CURLOPT_SSL_VERIFYPEER => !DEV_MODE,
|
||||||
]);
|
]);
|
||||||
@ -126,6 +140,7 @@ function resolveMitigations(string $buffStr, array $mitigIdMap): array {
|
|||||||
if (isset($seen[$name])) continue;
|
if (isset($seen[$name])) continue;
|
||||||
$seen[$name] = true;
|
$seen[$name] = true;
|
||||||
$result[] = [
|
$result[] = [
|
||||||
|
'key' => $mitigIdMap[$id]['key'] ?? $name,
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'dr' => $mitigIdMap[$id]['dr'],
|
'dr' => $mitigIdMap[$id]['dr'],
|
||||||
'buffType' => $mitigIdMap[$id]['buffType'],
|
'buffType' => $mitigIdMap[$id]['buffType'],
|
||||||
@ -146,7 +161,7 @@ function shieldsActiveAt(array $shieldTimeline, int $targetId, float $ts, array
|
|||||||
if ($iv['apply'] <= $ts && ($iv['remove'] === null || $iv['remove'] >= $ts - 200)) {
|
if ($iv['apply'] <= $ts && ($iv['remove'] === null || $iv['remove'] >= $ts - 200)) {
|
||||||
if (isset($mitigIdMap[$statusId])) {
|
if (isset($mitigIdMap[$statusId])) {
|
||||||
$m = $mitigIdMap[$statusId];
|
$m = $mitigIdMap[$statusId];
|
||||||
$result[] = ['name' => $m['name'], 'dr' => $m['dr'], 'buffType' => $m['buffType']];
|
$result[] = ['key' => $m['key'] ?? $m['name'], 'name' => $m['name'], 'dr' => $m['dr'], 'buffType' => $m['buffType']];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -161,7 +176,7 @@ $pdResult = fflogs_gql(<<<GQL
|
|||||||
reportData {
|
reportData {
|
||||||
report(code: "$reportCode") {
|
report(code: "$reportCode") {
|
||||||
playerDetails(fightIDs: [$fightId])
|
playerDetails(fightIDs: [$fightId])
|
||||||
masterData {
|
masterData(translate: $translate) {
|
||||||
abilities {
|
abilities {
|
||||||
gameID
|
gameID
|
||||||
name
|
name
|
||||||
@ -175,7 +190,7 @@ GQL);
|
|||||||
if (isset($pdResult['_reauth'])) { echo json_encode(['reauth' => true]); exit; }
|
if (isset($pdResult['_reauth'])) { echo json_encode(['reauth' => true]); exit; }
|
||||||
if (isset($pdResult['_curl_error'])) { http_response_code(502); echo json_encode(['error' => $pdResult['_curl_error']]); exit; }
|
if (isset($pdResult['_curl_error'])) { http_response_code(502); echo json_encode(['error' => $pdResult['_curl_error']]); exit; }
|
||||||
|
|
||||||
// abilityGameID → display name
|
// abilityGameID/statusID → display name
|
||||||
$abilityNames = [];
|
$abilityNames = [];
|
||||||
foreach ($pdResult['data']['reportData']['report']['masterData']['abilities'] ?? [] as $ab) {
|
foreach ($pdResult['data']['reportData']['report']['masterData']['abilities'] ?? [] as $ab) {
|
||||||
$abilityNames[(int)$ab['gameID']] = $ab['name'];
|
$abilityNames[(int)$ab['gameID']] = $ab['name'];
|
||||||
@ -187,12 +202,13 @@ foreach ($pdResult['data']['reportData']['report']['masterData']['abilities'] ??
|
|||||||
$mitigIdMap = [];
|
$mitigIdMap = [];
|
||||||
foreach ($abilityNames as $gameId => $name) {
|
foreach ($abilityNames as $gameId => $name) {
|
||||||
if (isset(MITIGATION_ABILITIES[$name])) {
|
if (isset(MITIGATION_ABILITIES[$name])) {
|
||||||
$mitigIdMap[$gameId] = array_merge(['name' => $name], MITIGATION_ABILITIES[$name]);
|
$mitigIdMap[$gameId] = array_merge(['key' => $name, 'name' => $name], MITIGATION_ABILITIES[$name]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (MITIGATION_ABILITIES as $name => $meta) {
|
foreach (MITIGATION_ABILITIES as $name => $meta) {
|
||||||
if (isset($meta['statusId']) && !isset($mitigIdMap[$meta['statusId']])) {
|
if (isset($meta['statusId']) && !isset($mitigIdMap[$meta['statusId']])) {
|
||||||
$mitigIdMap[$meta['statusId']] = array_merge(['name' => $name], $meta);
|
$displayName = $abilityNames[(int)$meta['statusId']] ?? $name;
|
||||||
|
$mitigIdMap[$meta['statusId']] = array_merge(['key' => $name, 'name' => $displayName], $meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,9 @@ $playerName = trim($_POST['player_name'] ?? '');
|
|||||||
$eventType = trim($_POST['event_type'] ?? '');
|
$eventType = trim($_POST['event_type'] ?? '');
|
||||||
$abilityId = (int)($_POST['ability_id'] ?? 0);
|
$abilityId = (int)($_POST['ability_id'] ?? 0);
|
||||||
$limit = max(1, min(500, (int)($_POST['limit'] ?? 20)));
|
$limit = max(1, min(500, (int)($_POST['limit'] ?? 20)));
|
||||||
|
$language = strtolower(trim($_POST['language'] ?? 'en'));
|
||||||
|
$language = in_array($language, ['en', 'de', 'fr', 'jp'], true) ? $language : 'en';
|
||||||
|
$translate = 'true';
|
||||||
$startOffset = (float)($_POST['start_offset'] ?? 0) * 1000; // s → ms
|
$startOffset = (float)($_POST['start_offset'] ?? 0) * 1000; // s → ms
|
||||||
$endOffset = isset($_POST['end_offset']) && $_POST['end_offset'] !== ''
|
$endOffset = isset($_POST['end_offset']) && $_POST['end_offset'] !== ''
|
||||||
? (float)$_POST['end_offset'] * 1000
|
? (float)$_POST['end_offset'] * 1000
|
||||||
@ -33,14 +36,24 @@ $queryEnd = min($queryEnd, $endTime);
|
|||||||
|
|
||||||
$token = $_SESSION['access_token'];
|
$token = $_SESSION['access_token'];
|
||||||
|
|
||||||
|
function localized_graphql_uri(string $language): string {
|
||||||
|
$host = [
|
||||||
|
'de' => 'de.fflogs.com',
|
||||||
|
'fr' => 'fr.fflogs.com',
|
||||||
|
'jp' => 'ja.fflogs.com',
|
||||||
|
][$language] ?? 'www.fflogs.com';
|
||||||
|
return preg_replace('#https://[^/]+#', 'https://' . $host, GRAPHQL_URI);
|
||||||
|
}
|
||||||
|
|
||||||
function dbg_gql(string $query): array {
|
function dbg_gql(string $query): array {
|
||||||
global $token;
|
global $token, $language;
|
||||||
$ch = curl_init(GRAPHQL_URI);
|
$acceptLanguage = $language === 'jp' ? 'ja' : $language;
|
||||||
|
$ch = curl_init(localized_graphql_uri($language));
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_POST => true,
|
CURLOPT_POST => true,
|
||||||
CURLOPT_POSTFIELDS => json_encode(['query' => $query]),
|
CURLOPT_POSTFIELDS => json_encode(['query' => $query]),
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $token],
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $token, 'Accept-Language: ' . $acceptLanguage],
|
||||||
CURLOPT_SSL_VERIFYPEER => !DEV_MODE,
|
CURLOPT_SSL_VERIFYPEER => !DEV_MODE,
|
||||||
]);
|
]);
|
||||||
$body = curl_exec($ch);
|
$body = curl_exec($ch);
|
||||||
@ -85,6 +98,7 @@ $result = dbg_gql(<<<GQL
|
|||||||
fightIDs: [$fightId],
|
fightIDs: [$fightId],
|
||||||
dataType: $dataType,
|
dataType: $dataType,
|
||||||
$includeResources
|
$includeResources
|
||||||
|
translate: $translate,
|
||||||
startTime: $queryStart,
|
startTime: $queryStart,
|
||||||
endTime: $queryEnd
|
endTime: $queryEnd
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -12,6 +12,8 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$reportCode = preg_replace('/[^a-zA-Z0-9]/', '', $_POST['report_code'] ?? '');
|
$reportCode = preg_replace('/[^a-zA-Z0-9]/', '', $_POST['report_code'] ?? '');
|
||||||
|
$language = strtolower(trim($_POST['language'] ?? 'en'));
|
||||||
|
$language = in_array($language, ['en', 'de', 'fr', 'jp'], true) ? $language : 'en';
|
||||||
|
|
||||||
if (strlen($reportCode) < 1) {
|
if (strlen($reportCode) < 1) {
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
@ -64,7 +66,17 @@ $payload = json_encode([
|
|||||||
'variables' => ['reportCode' => $reportCode],
|
'variables' => ['reportCode' => $reportCode],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$ch = curl_init(GRAPHQL_URI);
|
function localized_graphql_uri(string $language): string {
|
||||||
|
$host = [
|
||||||
|
'de' => 'de.fflogs.com',
|
||||||
|
'fr' => 'fr.fflogs.com',
|
||||||
|
'jp' => 'ja.fflogs.com',
|
||||||
|
][$language] ?? 'www.fflogs.com';
|
||||||
|
return preg_replace('#https://[^/]+#', 'https://' . $host, GRAPHQL_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
$acceptLanguage = $language === 'jp' ? 'ja' : $language;
|
||||||
|
$ch = curl_init(localized_graphql_uri($language));
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_POST => true,
|
CURLOPT_POST => true,
|
||||||
CURLOPT_POSTFIELDS => $payload,
|
CURLOPT_POSTFIELDS => $payload,
|
||||||
@ -72,6 +84,7 @@ curl_setopt_array($ch, [
|
|||||||
CURLOPT_HTTPHEADER => [
|
CURLOPT_HTTPHEADER => [
|
||||||
'Content-Type: application/json',
|
'Content-Type: application/json',
|
||||||
'Authorization: Bearer ' . $_SESSION['access_token'],
|
'Authorization: Bearer ' . $_SESSION['access_token'],
|
||||||
|
'Accept-Language: ' . $acceptLanguage,
|
||||||
],
|
],
|
||||||
CURLOPT_SSL_VERIFYPEER => !DEV_MODE,
|
CURLOPT_SSL_VERIFYPEER => !DEV_MODE,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -219,6 +219,9 @@
|
|||||||
if (!refId) {
|
if (!refId) {
|
||||||
refEvents = [];
|
refEvents = [];
|
||||||
refFightStart = 0;
|
refFightStart = 0;
|
||||||
|
refPlayers = [];
|
||||||
|
window.App.setUrlState?.({ compareReportCode: '', compareFightId: '' });
|
||||||
|
renderRefPlayers();
|
||||||
renderTimeline(lastEvents, lastFightStart);
|
renderTimeline(lastEvents, lastFightStart);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -239,25 +242,30 @@
|
|||||||
fight_id: refId,
|
fight_id: refId,
|
||||||
start_time: fight.startTime,
|
start_time: fight.startTime,
|
||||||
end_time: fight.endTime,
|
end_time: fight.endTime,
|
||||||
|
language: window.App.language,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (!json.error && !json.reauth) {
|
if (!json.error && !json.reauth) {
|
||||||
refEvents = json.aoe_events ?? [];
|
refEvents = json.aoe_events ?? [];
|
||||||
refFightStart = json.fight_start ?? fight.startTime;
|
refFightStart = json.fight_start ?? fight.startTime;
|
||||||
|
refPlayers = [];
|
||||||
|
window.App.setUrlState?.({
|
||||||
|
compareReportCode: '',
|
||||||
|
compareFightId: refId,
|
||||||
|
language: window.App.language,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch { }
|
} catch { }
|
||||||
refFightSelect.disabled = false;
|
refFightSelect.disabled = false;
|
||||||
|
renderRefPlayers();
|
||||||
renderTimeline(lastEvents, lastFightStart);
|
renderTimeline(lastEvents, lastFightStart);
|
||||||
});
|
});
|
||||||
|
|
||||||
let allSameReportFights = [];
|
let allSameReportFights = [];
|
||||||
|
|
||||||
function populateRefFightSelect() {
|
function populateRefFightSelect() {
|
||||||
const currentName = (window.App.fights ?? []).find(f => f.id === window.App.fightId)?.name;
|
const visible = allSameReportFights.filter(f => f.id !== window.App.fightId);
|
||||||
const visible = allSameReportFights.filter(f =>
|
|
||||||
f.id !== window.App.fightId && (!currentName || f.name === currentName)
|
|
||||||
);
|
|
||||||
refFightSelect.innerHTML = '<option value="">Kein Vergleich</option>';
|
refFightSelect.innerHTML = '<option value="">Kein Vergleich</option>';
|
||||||
visible.forEach(f => {
|
visible.forEach(f => {
|
||||||
const hp = f.kill ? 'Kill' : (f.fightPercentage != null ? f.fightPercentage.toFixed(2) + '%' : '?');
|
const hp = f.kill ? 'Kill' : (f.fightPercentage != null ? f.fightPercentage.toFixed(2) + '%' : '?');
|
||||||
@ -292,8 +300,7 @@
|
|||||||
refExtPanel.style.display = hidden ? '' : 'none';
|
refExtPanel.style.display = hidden ? '' : 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
refReportLoad.addEventListener('click', async () => {
|
async function loadExternalReport(code, preferredFightId = 0) {
|
||||||
const code = refReportInput.value.trim();
|
|
||||||
if (!code) return;
|
if (!code) return;
|
||||||
|
|
||||||
refReportLoad.disabled = true;
|
refReportLoad.disabled = true;
|
||||||
@ -303,7 +310,7 @@
|
|||||||
const res = await fetch('api/fight.php', {
|
const res = await fetch('api/fight.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
body: new URLSearchParams({ report_code: code }),
|
body: new URLSearchParams({ report_code: code, language: window.App.language }),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (json.reauth) { window.location.href = 'auth/start.php'; return; }
|
if (json.reauth) { window.location.href = 'auth/start.php'; return; }
|
||||||
@ -312,8 +319,7 @@
|
|||||||
extFights = fights;
|
extFights = fights;
|
||||||
extReportCode = code;
|
extReportCode = code;
|
||||||
|
|
||||||
const currentName = (window.App.fights ?? []).find(f => f.id === window.App.fightId)?.name;
|
const visibleExt = fights;
|
||||||
const visibleExt = currentName ? fights.filter(f => f.name === currentName) : fights;
|
|
||||||
refExtFightSelect.innerHTML = '<option value="">— Fight auswählen —</option>';
|
refExtFightSelect.innerHTML = '<option value="">— Fight auswählen —</option>';
|
||||||
visibleExt.forEach(f => {
|
visibleExt.forEach(f => {
|
||||||
const hp = f.kill ? 'Kill' : (f.fightPercentage != null ? f.fightPercentage.toFixed(2) + '%' : '?');
|
const hp = f.kill ? 'Kill' : (f.fightPercentage != null ? f.fightPercentage.toFixed(2) + '%' : '?');
|
||||||
@ -323,18 +329,27 @@
|
|||||||
refExtFightSelect.appendChild(opt);
|
refExtFightSelect.appendChild(opt);
|
||||||
});
|
});
|
||||||
refExtFightSelect.style.display = visibleExt.length ? '' : 'none';
|
refExtFightSelect.style.display = visibleExt.length ? '' : 'none';
|
||||||
|
refExtPanel.style.display = '';
|
||||||
|
if (preferredFightId) {
|
||||||
|
refExtFightSelect.value = String(preferredFightId);
|
||||||
|
await loadExternalCompare(preferredFightId);
|
||||||
|
}
|
||||||
} catch { }
|
} catch { }
|
||||||
|
|
||||||
refReportLoad.disabled = false;
|
refReportLoad.disabled = false;
|
||||||
refReportLoad.textContent = 'Laden';
|
refReportLoad.textContent = 'Laden';
|
||||||
|
}
|
||||||
|
|
||||||
|
refReportLoad.addEventListener('click', async () => {
|
||||||
|
await loadExternalReport(refReportInput.value.trim());
|
||||||
});
|
});
|
||||||
|
|
||||||
refExtFightSelect.addEventListener('change', async () => {
|
async function loadExternalCompare(refId) {
|
||||||
const refId = parseInt(refExtFightSelect.value, 10);
|
|
||||||
if (!refId) {
|
if (!refId) {
|
||||||
refEvents = [];
|
refEvents = [];
|
||||||
refFightStart = 0;
|
refFightStart = 0;
|
||||||
refPlayers = [];
|
refPlayers = [];
|
||||||
|
window.App.setUrlState?.({ compareReportCode: '', compareFightId: '' });
|
||||||
renderRefPlayers();
|
renderRefPlayers();
|
||||||
renderTimeline(lastEvents, lastFightStart);
|
renderTimeline(lastEvents, lastFightStart);
|
||||||
return;
|
return;
|
||||||
@ -356,6 +371,7 @@
|
|||||||
fight_id: refId,
|
fight_id: refId,
|
||||||
start_time: fight.startTime,
|
start_time: fight.startTime,
|
||||||
end_time: fight.endTime,
|
end_time: fight.endTime,
|
||||||
|
language: window.App.language,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
@ -363,11 +379,20 @@
|
|||||||
refEvents = json.aoe_events ?? [];
|
refEvents = json.aoe_events ?? [];
|
||||||
refFightStart = json.fight_start ?? fight.startTime;
|
refFightStart = json.fight_start ?? fight.startTime;
|
||||||
refPlayers = json.players ?? [];
|
refPlayers = json.players ?? [];
|
||||||
|
window.App.setUrlState?.({
|
||||||
|
compareReportCode: extReportCode,
|
||||||
|
compareFightId: refId,
|
||||||
|
language: window.App.language,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch { }
|
} catch { }
|
||||||
refExtFightSelect.disabled = false;
|
refExtFightSelect.disabled = false;
|
||||||
renderRefPlayers();
|
renderRefPlayers();
|
||||||
renderTimeline(lastEvents, lastFightStart);
|
renderTimeline(lastEvents, lastFightStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
refExtFightSelect.addEventListener('change', async () => {
|
||||||
|
await loadExternalCompare(parseInt(refExtFightSelect.value, 10));
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Timeline rendering ────────────────────────────────────────────────────
|
// ── Timeline rendering ────────────────────────────────────────────────────
|
||||||
@ -405,24 +430,25 @@
|
|||||||
if (!visibleTargets.length) return '';
|
if (!visibleTargets.length) return '';
|
||||||
|
|
||||||
// Collect boss debuffs (Reprisal/Feint/Addle) once at event level
|
// Collect boss debuffs (Reprisal/Feint/Addle) once at event level
|
||||||
const seenDebuffNames = new Set();
|
const seenDebuffKeys = new Set();
|
||||||
const eventDebuffs = [];
|
const eventDebuffs = [];
|
||||||
for (const t of visibleTargets) {
|
for (const t of visibleTargets) {
|
||||||
for (const m of (t.mitigations ?? [])) {
|
for (const m of (t.mitigations ?? [])) {
|
||||||
if (m.buffType === 'debuff' && !seenDebuffNames.has(m.name)) {
|
const key = m.key ?? m.name;
|
||||||
seenDebuffNames.add(m.name);
|
if (m.buffType === 'debuff' && !seenDebuffKeys.has(key)) {
|
||||||
|
seenDebuffKeys.add(key);
|
||||||
eventDebuffs.push(m);
|
eventDebuffs.push(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const eventMissingDebuffs = refEv
|
const eventMissingDebuffs = refEv
|
||||||
? (refEv.targets[0]?.mitigations ?? []).filter(m => m.buffType === 'debuff' && !seenDebuffNames.has(m.name))
|
? (refEv.targets[0]?.mitigations ?? []).filter(m => m.buffType === 'debuff' && !seenDebuffKeys.has(m.key ?? m.name))
|
||||||
: [];
|
: [];
|
||||||
const debuffIconsHtml = [
|
const debuffIconsHtml = [
|
||||||
...eventDebuffs.map(m => ({ ...m, missing: false })),
|
...eventDebuffs.map(m => ({ ...m, missing: false })),
|
||||||
...eventMissingDebuffs.map(m => ({ ...m, missing: true })),
|
...eventMissingDebuffs.map(m => ({ ...m, missing: true })),
|
||||||
].map(m => {
|
].map(m => {
|
||||||
const iconSrc = MITIG_ICONS[m.name];
|
const iconSrc = MITIG_ICONS[m.key] ?? MITIG_ICONS[m.name];
|
||||||
if (!iconSrc) return '';
|
if (!iconSrc) return '';
|
||||||
const dr = m.dr > 0 ? ` −${m.dr}%` : '';
|
const dr = m.dr > 0 ? ` −${m.dr}%` : '';
|
||||||
return m.missing
|
return m.missing
|
||||||
@ -447,15 +473,15 @@
|
|||||||
</div>`;
|
</div>`;
|
||||||
})() : '';
|
})() : '';
|
||||||
|
|
||||||
const currentMitigNames = new Set((t.mitigations ?? []).map(m => m.name));
|
const currentMitigKeys = new Set((t.mitigations ?? []).map(m => m.key ?? m.name));
|
||||||
const refTarget = refEv?.targets?.find(rt => rt.name === t.name);
|
const refTarget = refEv?.targets?.find(rt => rt.name === t.name);
|
||||||
const missingMitigs = refTarget
|
const missingMitigs = refTarget
|
||||||
? (refTarget.mitigations ?? []).filter(m => m.buffType === 'buff' && !currentMitigNames.has(m.name))
|
? (refTarget.mitigations ?? []).filter(m => m.buffType === 'buff' && !currentMitigKeys.has(m.key ?? m.name))
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
// DR buff icons (shown below player box)
|
// DR buff icons (shown below player box)
|
||||||
const mitigIcons = (t.mitigations ?? []).filter(m => m.buffType === 'buff').map(m => {
|
const mitigIcons = (t.mitigations ?? []).filter(m => m.buffType === 'buff').map(m => {
|
||||||
const iconSrc = MITIG_ICONS[m.name];
|
const iconSrc = MITIG_ICONS[m.key] ?? MITIG_ICONS[m.name];
|
||||||
if (!iconSrc) return '';
|
if (!iconSrc) return '';
|
||||||
const dr = m.dr > 0 ? ` −${m.dr}%` : '';
|
const dr = m.dr > 0 ? ` −${m.dr}%` : '';
|
||||||
return `<img class="aoe-target-buff-icon" src="${iconSrc}" alt="${m.name}" title="${m.name}${dr}">`;
|
return `<img class="aoe-target-buff-icon" src="${iconSrc}" alt="${m.name}" title="${m.name}${dr}">`;
|
||||||
@ -464,7 +490,7 @@
|
|||||||
// Shield tooltip on absorbed value
|
// Shield tooltip on absorbed value
|
||||||
const activeShields = (t.mitigations ?? []).filter(m => m.buffType === 'shield');
|
const activeShields = (t.mitigations ?? []).filter(m => m.buffType === 'shield');
|
||||||
const missingShields = refTarget
|
const missingShields = refTarget
|
||||||
? (refTarget.mitigations ?? []).filter(m => m.buffType === 'shield' && !currentMitigNames.has(m.name))
|
? (refTarget.mitigations ?? []).filter(m => m.buffType === 'shield' && !currentMitigKeys.has(m.key ?? m.name))
|
||||||
: [];
|
: [];
|
||||||
const shieldLines = [
|
const shieldLines = [
|
||||||
...activeShields.map(s => s.name),
|
...activeShields.map(s => s.name),
|
||||||
@ -504,11 +530,11 @@
|
|||||||
const currentByName = {};
|
const currentByName = {};
|
||||||
ev.targets.forEach(t => { currentByName[t.name] = t; });
|
ev.targets.forEach(t => { currentByName[t.name] = t; });
|
||||||
|
|
||||||
const seenRefDebuffNames = new Set();
|
const seenRefDebuffKeys = new Set();
|
||||||
const refDebuffIconsHtml = refVisible.flatMap(t => (t.mitigations ?? []))
|
const refDebuffIconsHtml = refVisible.flatMap(t => (t.mitigations ?? []))
|
||||||
.filter(m => m.buffType === 'debuff' && !seenRefDebuffNames.has(m.name) && seenRefDebuffNames.add(m.name))
|
.filter(m => m.buffType === 'debuff' && !seenRefDebuffKeys.has(m.key ?? m.name) && seenRefDebuffKeys.add(m.key ?? m.name))
|
||||||
.map(m => {
|
.map(m => {
|
||||||
const iconSrc = MITIG_ICONS[m.name];
|
const iconSrc = MITIG_ICONS[m.key] ?? MITIG_ICONS[m.name];
|
||||||
if (!iconSrc) return '';
|
if (!iconSrc) return '';
|
||||||
const dr = m.dr > 0 ? ` −${m.dr}%` : '';
|
const dr = m.dr > 0 ? ` −${m.dr}%` : '';
|
||||||
return `<img class="aoe-target-buff-icon" src="${iconSrc}" alt="${m.name}" title="${m.name}${dr}">`;
|
return `<img class="aoe-target-buff-icon" src="${iconSrc}" alt="${m.name}" title="${m.name}${dr}">`;
|
||||||
@ -523,13 +549,13 @@
|
|||||||
? `<span class="${diff > 0 ? 'aoe-delta-worse' : 'aoe-delta-better'}">${diff > 0 ? '+' : '-'}${fmtDmg(Math.abs(diff))}</span>`
|
? `<span class="${diff > 0 ? 'aoe-delta-worse' : 'aoe-delta-better'}">${diff > 0 ? '+' : '-'}${fmtDmg(Math.abs(diff))}</span>`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
const currMitigNames = new Set((curr?.mitigations ?? []).map(m => m.name));
|
const currMitigKeys = new Set((curr?.mitigations ?? []).map(m => m.key ?? m.name));
|
||||||
|
|
||||||
const refMitigIcons = (t.mitigations ?? []).filter(m => m.buffType === 'buff').map(m => {
|
const refMitigIcons = (t.mitigations ?? []).filter(m => m.buffType === 'buff').map(m => {
|
||||||
const iconSrc = MITIG_ICONS[m.name];
|
const iconSrc = MITIG_ICONS[m.key] ?? MITIG_ICONS[m.name];
|
||||||
if (!iconSrc) return '';
|
if (!iconSrc) return '';
|
||||||
const dr = m.dr > 0 ? ` −${m.dr}%` : '';
|
const dr = m.dr > 0 ? ` −${m.dr}%` : '';
|
||||||
const missing = !currMitigNames.has(m.name);
|
const missing = !currMitigKeys.has(m.key ?? m.name);
|
||||||
const cls = missing ? ' aoe-buff-ref-unique' : '';
|
const cls = missing ? ' aoe-buff-ref-unique' : '';
|
||||||
const titleSufx = missing ? ' (fehlt im aktuellen Pull)' : '';
|
const titleSufx = missing ? ' (fehlt im aktuellen Pull)' : '';
|
||||||
return `<img class="aoe-target-buff-icon${cls}" src="${iconSrc}" alt="${m.name}" title="${m.name}${dr}${titleSufx}">`;
|
return `<img class="aoe-target-buff-icon${cls}" src="${iconSrc}" alt="${m.name}" title="${m.name}${dr}${titleSufx}">`;
|
||||||
@ -537,7 +563,7 @@
|
|||||||
|
|
||||||
const refShields = (t.mitigations ?? []).filter(m => m.buffType === 'shield');
|
const refShields = (t.mitigations ?? []).filter(m => m.buffType === 'shield');
|
||||||
const refShieldTitle = refShields.length
|
const refShieldTitle = refShields.length
|
||||||
? refShields.map(s => currMitigNames.has(s.name) ? s.name : `${s.name} [fehlt im aktuellen Pull]`).join('\n')
|
? refShields.map(s => currMitigKeys.has(s.key ?? s.name) ? s.name : `${s.name} [fehlt im aktuellen Pull]`).join('\n')
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
@ -609,7 +635,7 @@
|
|||||||
const res = await fetch('api/analysis.php', {
|
const res = await fetch('api/analysis.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
body: new URLSearchParams({ report_code: reportCode, fight_id: fightId, start_time: fightStart, end_time: fightEnd }),
|
body: new URLSearchParams({ report_code: reportCode, fight_id: fightId, start_time: fightStart, end_time: fightEnd, language: window.App.language }),
|
||||||
});
|
});
|
||||||
json = await res.json();
|
json = await res.json();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -634,6 +660,18 @@
|
|||||||
onFightSelected: load,
|
onFightSelected: load,
|
||||||
onTabOpen: load,
|
onTabOpen: load,
|
||||||
onFightsLoaded: onFightsLoaded,
|
onFightsLoaded: onFightsLoaded,
|
||||||
|
async selectSharedCompare(fightId, reportCode = '') {
|
||||||
|
if (!fightId) return;
|
||||||
|
if (reportCode && reportCode !== window.App?.reportCode) {
|
||||||
|
refReportInput.value = reportCode;
|
||||||
|
await loadExternalReport(reportCode, fightId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ([...refFightSelect.options].some(opt => parseInt(opt.value, 10) === fightId)) {
|
||||||
|
refFightSelect.value = String(fightId);
|
||||||
|
refFightSelect.dispatchEvent(new Event('change'));
|
||||||
|
}
|
||||||
|
},
|
||||||
reset() {
|
reset() {
|
||||||
lastFightId = null;
|
lastFightId = null;
|
||||||
refEvents = [];
|
refEvents = [];
|
||||||
|
|||||||
130
js/app.js
130
js/app.js
@ -1,5 +1,5 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
window.App = { reportCode: null, fightId: null, fightStart: 0, fightEnd: 0, phases: [], fights: [] };
|
window.App = { reportCode: null, fightId: null, fightStart: 0, fightEnd: 0, language: 'en', phases: [], fights: [] };
|
||||||
|
|
||||||
const form = document.getElementById('report-form');
|
const form = document.getElementById('report-form');
|
||||||
const output = document.getElementById('output');
|
const output = document.getElementById('output');
|
||||||
@ -7,6 +7,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const initialHint = document.getElementById('initial-hint');
|
const initialHint = document.getElementById('initial-hint');
|
||||||
const fightSelectCard = document.getElementById('fight-select-card');
|
const fightSelectCard = document.getElementById('fight-select-card');
|
||||||
const fightSelect = document.getElementById('fight-select');
|
const fightSelect = document.getElementById('fight-select');
|
||||||
|
const languageSelect = document.getElementById('language-select');
|
||||||
const explorerCard = document.getElementById('event-explorer-card');
|
const explorerCard = document.getElementById('event-explorer-card');
|
||||||
const exLoadBtn = document.getElementById('ex-load-btn');
|
const exLoadBtn = document.getElementById('ex-load-btn');
|
||||||
const exAbilitySelect = document.getElementById('ex-ability');
|
const exAbilitySelect = document.getElementById('ex-ability');
|
||||||
@ -14,6 +15,68 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
let allFights = [];
|
let allFights = [];
|
||||||
|
|
||||||
|
function getUrlState() {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const pick = (...names) => {
|
||||||
|
for (const name of names) {
|
||||||
|
const value = params.get(name);
|
||||||
|
if (value !== null && value !== '') return value;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
reportCode: pick('report_code', 'reportCode', 'report'),
|
||||||
|
fightId: parseInt(pick('fightid', 'fight_id', 'fightId'), 10) || 0,
|
||||||
|
compareReportCode: pick('compare_report_code', 'compareReportCode', 'compare_report', 'ref_report'),
|
||||||
|
compareFightId: parseInt(pick('comparefightid', 'compare_fight_id', 'compareFightId', 'ref_fight_id'), 10) || 0,
|
||||||
|
language: pick('language', 'lang'),
|
||||||
|
translate: pick('translate'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeLanguage(value, fallback = 'en') {
|
||||||
|
const lang = String(value || '').toLowerCase();
|
||||||
|
return ['en', 'de', 'fr', 'jp'].includes(lang) ? lang : fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUrlState(updates) {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const setOrDelete = (name, value) => {
|
||||||
|
if (value === null || value === undefined || value === '') url.searchParams.delete(name);
|
||||||
|
else url.searchParams.set(name, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
if ('reportCode' in updates) setOrDelete('report_code', updates.reportCode);
|
||||||
|
if ('fightId' in updates) setOrDelete('fightid', updates.fightId);
|
||||||
|
if ('compareReportCode' in updates) setOrDelete('compare_report_code', updates.compareReportCode);
|
||||||
|
if ('compareFightId' in updates) setOrDelete('comparefightid', updates.compareFightId);
|
||||||
|
if ('language' in updates) {
|
||||||
|
setOrDelete('language', normalizeLanguage(updates.language));
|
||||||
|
url.searchParams.delete('translate');
|
||||||
|
}
|
||||||
|
|
||||||
|
window.history.replaceState(null, '', url);
|
||||||
|
}
|
||||||
|
window.App.setUrlState = setUrlState;
|
||||||
|
|
||||||
|
const initialUrlState = getUrlState();
|
||||||
|
const storedLanguage = localStorage.getItem('ff14-mitigator-language');
|
||||||
|
const legacyTranslateLanguage = initialUrlState.translate === '1' ? 'de' : 'en';
|
||||||
|
languageSelect.value = normalizeLanguage(
|
||||||
|
initialUrlState.language || storedLanguage,
|
||||||
|
initialUrlState.translate !== '' ? legacyTranslateLanguage : 'en'
|
||||||
|
);
|
||||||
|
window.App.language = languageSelect.value;
|
||||||
|
|
||||||
|
languageSelect.addEventListener('change', () => {
|
||||||
|
window.App.language = normalizeLanguage(languageSelect.value);
|
||||||
|
localStorage.setItem('ff14-mitigator-language', window.App.language);
|
||||||
|
setUrlState({ language: window.App.language });
|
||||||
|
if (window.App.reportCode) {
|
||||||
|
loadReport(window.App.reportCode, window.App.fightId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const codeInput = form.elements['report_code'];
|
const codeInput = form.elements['report_code'];
|
||||||
codeInput.addEventListener('input', () => {
|
codeInput.addEventListener('input', () => {
|
||||||
const match = codeInput.value.match(/fflogs\.com\/reports\/([A-Za-z0-9]+)/);
|
const match = codeInput.value.match(/fflogs\.com\/reports\/([A-Za-z0-9]+)/);
|
||||||
@ -38,12 +101,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
outputCard.style.display = 'block';
|
outputCard.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
fightSelect.addEventListener('change', () => {
|
function openAnalysisTab() {
|
||||||
if (!fightSelect.value) return;
|
document.querySelector('.tabs .tab[data-tab="analysis"]')?.click();
|
||||||
const id = parseInt(fightSelect.value, 10);
|
}
|
||||||
const fight = allFights.find(f => f.id === id);
|
|
||||||
if (!fight) return;
|
|
||||||
|
|
||||||
|
function selectFight(id, updateUrl = true) {
|
||||||
|
const fight = allFights.find(f => f.id === id);
|
||||||
|
if (!fight) return false;
|
||||||
|
|
||||||
|
fightSelect.value = String(id);
|
||||||
window.App.fightId = id;
|
window.App.fightId = id;
|
||||||
window.App.fightStart = fight.startTime;
|
window.App.fightStart = fight.startTime;
|
||||||
window.App.fightEnd = fight.endTime;
|
window.App.fightEnd = fight.endTime;
|
||||||
@ -51,8 +117,21 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
displayFight(fight);
|
displayFight(fight);
|
||||||
explorerCard.style.display = 'block';
|
explorerCard.style.display = 'block';
|
||||||
|
if (updateUrl) {
|
||||||
|
setUrlState({
|
||||||
|
reportCode: window.App.reportCode,
|
||||||
|
fightId: id,
|
||||||
|
language: window.App.language,
|
||||||
|
});
|
||||||
|
}
|
||||||
window.analysisTab?.onFightSelected?.();
|
window.analysisTab?.onFightSelected?.();
|
||||||
loadAbilities(id, fight.startTime, fight.endTime);
|
loadAbilities(id, fight.startTime, fight.endTime);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fightSelect.addEventListener('change', () => {
|
||||||
|
if (!fightSelect.value) return;
|
||||||
|
selectFight(parseInt(fightSelect.value, 10));
|
||||||
});
|
});
|
||||||
|
|
||||||
function buildPhases(fight) {
|
function buildPhases(fight) {
|
||||||
@ -78,6 +157,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
fight_id: fightId,
|
fight_id: fightId,
|
||||||
start_time: startTime,
|
start_time: startTime,
|
||||||
end_time: endTime,
|
end_time: endTime,
|
||||||
|
language: window.App.language,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
@ -113,6 +193,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
fight_id: window.App.fightId,
|
fight_id: window.App.fightId,
|
||||||
start_time: window.App.fightStart,
|
start_time: window.App.fightStart,
|
||||||
end_time: window.App.fightEnd,
|
end_time: window.App.fightEnd,
|
||||||
|
language: window.App.language,
|
||||||
data_type: document.getElementById('ex-data-type').value,
|
data_type: document.getElementById('ex-data-type').value,
|
||||||
ability_id: exAbilitySelect.value,
|
ability_id: exAbilitySelect.value,
|
||||||
event_type: document.getElementById('ex-event-type').value.trim(),
|
event_type: document.getElementById('ex-event-type').value.trim(),
|
||||||
@ -136,9 +217,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
form.addEventListener('submit', async (e) => {
|
async function loadReport(reportCode, preferredFightId = 0) {
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
initialHint.style.display = 'none';
|
initialHint.style.display = 'none';
|
||||||
outputCard.style.display = 'block';
|
outputCard.style.display = 'block';
|
||||||
output.textContent = '// fetching...';
|
output.textContent = '// fetching...';
|
||||||
@ -147,21 +226,29 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
fightSelect.innerHTML = '<option value="">— Fight auswählen —</option>';
|
fightSelect.innerHTML = '<option value="">— Fight auswählen —</option>';
|
||||||
allFights = [];
|
allFights = [];
|
||||||
|
|
||||||
const reportCode = form.elements['report_code'].value.trim();
|
|
||||||
window.App.reportCode = reportCode;
|
window.App.reportCode = reportCode;
|
||||||
window.App.fightId = null;
|
window.App.fightId = null;
|
||||||
window.App.fightStart = 0;
|
window.App.fightStart = 0;
|
||||||
window.App.fightEnd = 0;
|
window.App.fightEnd = 0;
|
||||||
|
window.App.language = normalizeLanguage(languageSelect.value);
|
||||||
window.App.phases = [];
|
window.App.phases = [];
|
||||||
window.App.fights = [];
|
window.App.fights = [];
|
||||||
window.analysisTab?.reset?.();
|
window.analysisTab?.reset?.();
|
||||||
|
localStorage.setItem('ff14-mitigator-language', window.App.language);
|
||||||
|
setUrlState({
|
||||||
|
reportCode,
|
||||||
|
fightId: '',
|
||||||
|
compareReportCode: '',
|
||||||
|
compareFightId: '',
|
||||||
|
language: window.App.language,
|
||||||
|
});
|
||||||
|
|
||||||
let response, json;
|
let response, json;
|
||||||
try {
|
try {
|
||||||
response = await fetch('api/fight.php', {
|
response = await fetch('api/fight.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
body: new URLSearchParams({ report_code: reportCode }),
|
body: new URLSearchParams({ report_code: reportCode, language: window.App.language }),
|
||||||
});
|
});
|
||||||
json = await response.json();
|
json = await response.json();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -204,7 +291,26 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
window.App.fights = allFights;
|
window.App.fights = allFights;
|
||||||
fightSelectCard.style.display = 'block';
|
fightSelectCard.style.display = 'block';
|
||||||
output.textContent = '// Fight auswählen ↑';
|
|
||||||
window.analysisTab?.onFightsLoaded?.(allFights);
|
window.analysisTab?.onFightsLoaded?.(allFights);
|
||||||
|
|
||||||
|
if (preferredFightId && selectFight(preferredFightId, true)) return;
|
||||||
|
output.textContent = '// Fight auswählen ↑';
|
||||||
|
}
|
||||||
|
|
||||||
|
form.addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
await loadReport(form.elements['report_code'].value.trim());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (initialUrlState.reportCode) {
|
||||||
|
form.elements['report_code'].value = initialUrlState.reportCode;
|
||||||
|
loadReport(initialUrlState.reportCode, initialUrlState.fightId).then(() => {
|
||||||
|
if (initialUrlState.fightId) {
|
||||||
|
openAnalysisTab();
|
||||||
|
}
|
||||||
|
if (initialUrlState.compareFightId) {
|
||||||
|
window.analysisTab?.selectSharedCompare?.(initialUrlState.compareFightId, initialUrlState.compareReportCode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,6 +13,15 @@
|
|||||||
required
|
required
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="fg">
|
||||||
|
<label>Namen</label>
|
||||||
|
<select name="language" id="language-select">
|
||||||
|
<option value="en">EN</option>
|
||||||
|
<option value="de">DE</option>
|
||||||
|
<option value="fr">FR</option>
|
||||||
|
<option value="jp">JP</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<button class="btn btn-gold" type="submit" style="align-self:flex-end">Fetch</button>
|
<button class="btn btn-gold" type="submit" style="align-self:flex-end">Fetch</button>
|
||||||
<a class="btn" href="auth/start.php" style="align-self:flex-end;text-decoration:none">Reconnect</a>
|
<a class="btn" href="auth/start.php" style="align-self:flex-end;text-decoration:none">Reconnect</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user