FFlogs XIVAnalysis Button
@match: https://www.fflogs.com/reports/*
Adds a button linking to XIVAnalysis based on the current fight parameter in FFLogs reports. Generated by AI so don't judge it too hard.
// ==UserScript==
// @name FFLogs → XIVAnalysis Fight Button
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Adds a button linking to XIVAnalysis based on the current fight parameter in FFLogs reports.
// @author Your Name
// @match https://www.fflogs.com/reports/*
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// Returns the current "fight" parameter value (or null if not set)
function getFightParam() {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('fight');
}
// Returns the report id from the URL (assuming URL is /reports/{reportID}...)
function getReportID() {
const parts = window.location.pathname.split('/');
const idx = parts.indexOf("reports");
return (idx !== -1 && parts.length > idx + 1) ? parts[idx + 1] : null;
}
// Update or create the XIVAnalysis button based on the current URL.
function updateButton() {
const fight = getFightParam();
const reportID = getReportID();
// If there's no fight parameter or reportID, remove any existing button.
if (!fight || !reportID) {
const existing = document.getElementById('xivanalysis-button');
if (existing) existing.remove();
return;
}
// Build the new URL: https://xivanalysis.com/fflogs/{reportID}/{fight}
const linkURL = `https://xivanalysis.com/fflogs/\${reportID}/\${fight}\`;
// Check if our button already exists
let button = document.getElementById('xivanalysis-button');
if (!button) {
// Create the button element (styled similar to FFLogs tabs)
button = document.createElement('a');
button.id = 'xivanalysis-button';
button.className = 'big-tab view-type-tab';
button.innerHTML = \`
<span class="zmdi zmdi-search-in-file"></span>
<span class="big-tab-text"><br>XIVAnalysis</span>
\`;
// Append the button to the tab container if available
const container = document.getElementById('top-level-view-tabs');
if (container) {
container.appendChild(button);
} else {
// Otherwise, append to body (or choose a fallback container)
document.body.appendChild(button);
}
}
// Update the button's link URL
button.href = linkURL;
}
// --- Listen for URL changes without full reloads ---
// Override pushState/replaceState to dispatch a custom event
(function(history) {
const pushState = history.pushState;
const replaceState = history.replaceState;
history.pushState = function(state) {
const ret = pushState.apply(history, arguments);
window.dispatchEvent(new Event('locationchange'));
return ret;
};
history.replaceState = function(state) {
const ret = replaceState.apply(history, arguments);
window.dispatchEvent(new Event('locationchange'));
return ret;
};
})(window.history);
// Also listen for popstate events (back/forward)
window.addEventListener('popstate', () => {
window.dispatchEvent(new Event('locationchange'));
});
// Run updateButton() whenever the URL changes
window.addEventListener('locationchange', updateButton);
// Initial run on page load
updateButton();
})();