// ==UserScript==
// @name MZ - Multiple League Standings in a Single View
// @namespace douglaskampl
// @version 3.4
// @description Displays all leagues or world leagues from a country or region, grouped by div, in a single view
// @author Douglas
// @match https://www.managerzone.com/?p=team
// @icon https://www.google.com/s2/favicons?sz=64&domain=managerzone.com
// @grant GM_addStyle
// @license MIT
// ==/UserScript==
GM_addStyle(`
#league-buttons-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 20px;
}
#league-toggle-button {
margin: 4px;
padding: 8px 16px;
border: none;
border-radius: 6px;
background-color: #570987;
color: #ffffff;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
}
#league-toggle-button:hover {
background-color: #a020f0;
}
.league-button {
margin: 4px;
padding: 8px 16px;
border: none;
border-radius: 6px;
background-color: navy;
color: #ffffff;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
opacity: 0;
display: none;
}
.league-button:hover {
background-color: #000066;
}
#leagues-modal {
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.75);
display: flex;
justify-content: center;
align-items: flex-start;
overflow-y: auto;
padding: 40px 20px;
}
#leagues-modal-content {
background-color: #ffffff;
background-image: url('https://s1.ax1x.com/2023/06/25/pCNmCSH.jpg');
border-radius: 8px;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
padding: 24px;
width: 90%;
max-width: 1200px;
position: relative;
max-height: 85vh;
overflow-y: auto;
}
#leagues-modal-title {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
font-size: 24px;
color: #1a1a1a;
margin-bottom: 24px;
text-align: center;
}
#leagues-modal-close-button {
position: absolute;
top: 16px;
right: 16px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666666;
padding: 4px 8px;
transition: color 0.2s ease;
}
#leagues-modal-close-button:hover {
color: #1a1a1a;
}
#country-dropdown {
width: 200px;
padding: 8px;
margin-bottom: 16px;
border: 1px solid #cccccc;
border-radius: 4px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
}
#leagues-tabs {
display: flex;
gap: 8px;
margin-bottom: 24px;
flex-wrap: wrap;
}
#leagues-tabs button {
padding: 8px 16px;
border: solid black 1px;
border-radius: 4px;
background-color: #f0f0f0;
color: #1a1a1a;
cursor: pointer;
transition: all 0.2s ease;
}
#leagues-tabs button:hover {
background-color: #e0e0e0;
}
#league-tables-container {
width: 100%;
}
#league-tables-container p {
font-size: 16px;
margin: 20px 0;
font-style: italic;
color: navy;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
}
#league-tables-container .nice_table {
width: 100%;
border-collapse: collapse;
margin-bottom: 24px;
background-color: #ffffff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
#league-tables-container .nice_table th {
background-color: #f5f5f5;
padding: 12px;
text-align: left;
border-bottom: 2px solid #e0e0e0;
}
#league-tables-container .nice_table td {
padding: 12px;
border-bottom: 1px solid #e0e0e0;
}
#league-tables-container .nice_table tr:hover {
background-color: #f8f8f8;
}
#league-tables-container .nice_table .seriesHeader th {
color: black;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeOut {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(10px); }
}
.fade-in {
animation: fadeIn 0.2s ease forwards;
}
.fade-out {
animation: fadeOut 0.2s ease forwards;
}
.loader {
width: 10px;
height: 10px;
border: 3px solid #f3f3f3;
border-top: 3px solid navy;
border-radius: 50%;
display: inline-block;
box-sizing: border-box;
animation: rotation 1s linear infinite;
margin-bottom: 10px;
}
@keyframes rotation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.9);
display: none;
z-index: 10;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.loading-text {
color: navy;
font-size: 14px;
margin-top: 10px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
}
`);
(function () {
const TOGGLE_TEXT_UP = "UP 上";
const TOGGLE_TEXT_DOWN = "DOWN 下";
const infoAboutTeam = document.getElementById("infoAboutTeam");
const teamStadiumWrapper = document.getElementById("team-stadium-wrapper");
const sport = new URL(document.querySelector("#shortcut_link_thezone").href).searchParams.get("sport");
const teamId = RegExp(/\((\d+)\)/).exec(infoAboutTeam.querySelector("dd").textContent)[1];
const seniorLeagues = getSeniorLeagues();
const worldLeagues = { World: getWorldLeaguesObj() };
const uxxLeagues = getUxxLeagues();
if (infoAboutTeam && teamStadiumWrapper) {
initializeInterface();
}
function initializeInterface() {
const mainContainer = document.createElement("div");
mainContainer.id = "league-buttons-container";
const toggleBtn = createToggleButton();
toggleBtn.onclick = toggleLeagueButtons;
const buttonNames = [
"Senior Leagues",
"World Leagues",
"U18 World Leagues",
"U21 World Leagues",
"U23 World Leagues",
"U18 Leagues",
"U21 Leagues",
"U23 Leagues"
];
buttonNames.forEach(name => {
const btn = document.createElement("button");
btn.className = "league-button";
btn.id = `league-button-${name.toLowerCase()}`;
btn.textContent = name;
btn.style.display = "none";
btn.onclick = () => {
const leaguesModal = createLeaguesModal("leagues-modal", btn);
document.body.appendChild(leaguesModal);
};
mainContainer.appendChild(btn);
});
mainContainer.appendChild(toggleBtn);
teamStadiumWrapper.appendChild(mainContainer);
}
function createToggleButton() {
const btn = document.createElement("button");
btn.id = "league-toggle-button";
btn.textContent = TOGGLE_TEXT_DOWN;
return btn;
}
function toggleLeagueButtons() {
const container = document.getElementById("league-buttons-container");
const buttons = container.querySelectorAll(".league-button");
const toggleBtn = document.getElementById("league-toggle-button");
buttons.forEach(btn => {
if (btn.style.display === "none") {
btn.style.display = "block";
btn.classList.remove("fade-out");
btn.classList.add("fade-in");
toggleBtn.textContent = TOGGLE_TEXT_UP;
} else {
btn.classList.remove("fade-in");
btn.classList.add("fade-out");
setTimeout(() => btn.style.display = "none", 200);
toggleBtn.textContent = TOGGLE_TEXT_DOWN;
}
});
}
function createLeaguesModal(modalId, button) {
const leagueType = getLeagueTypeFromButtonId(button.id);
const modal = document.createElement("div");
modal.id = modalId;
const content = document.createElement("div");
content.id = "leagues-modal-content";
const title = document.createElement("h2");
title.id = "leagues-modal-title";
title.textContent = button.textContent;
content.appendChild(title);
const closeButton = document.createElement("button");
closeButton.id = "leagues-modal-close-button";
closeButton.textContent = "×";
closeButton.onclick = () => modal.remove();
content.appendChild(closeButton);
const tablesContainer = document.createElement("div");
tablesContainer.id = "league-tables-container";
const countryDropdown = createCountryDropdown(leagueType);
content.appendChild(countryDropdown);
const tabContainer = createTabContainer(leagueType, countryDropdown.value, tablesContainer);
content.appendChild(tabContainer);
content.appendChild(tablesContainer);
modal.appendChild(content);
modal.onclick = (e) => { if (e.target === modal) { modal.remove(); } };
return modal;
}
function createCountryDropdown(leagueType) {
const dropdown = document.createElement("select");
dropdown.id = "country-dropdown";
if (!["world", "u18_world", "u21_world", "u23_world"].includes(leagueType)) {
const allOption = document.createElement("option");
allOption.value = "All";
allOption.text = "All";
dropdown.appendChild(allOption);
}
const countries = getCountries(leagueType);
countries.forEach(country => {
const option = document.createElement("option");
option.value = country;
option.text = country;
dropdown.appendChild(option);
});
dropdown.onchange = function () {
const tablesContainer = document.getElementById("league-tables-container");
const tabs = document.getElementById("leagues-tabs");
while (tabs.firstChild) tabs.removeChild(tabs.firstChild);
while (tablesContainer.firstChild) tablesContainer.removeChild(tablesContainer.firstChild);
const newTabs = createTabContainer(leagueType, this.value, tablesContainer);
tabs.parentNode.replaceChild(newTabs, tabs);
if (newTabs.firstChild) { newTabs.firstChild.click(); }
};
return dropdown;
}
function createTabContainer(leagueType, country, tablesContainer) {
const container = document.createElement("div");
container.id = "leagues-tabs";
const leagues = getLeaguesObjFromLeagueType(leagueType, country);
Object.keys(leagues).forEach(league => {
const tab = document.createElement("button");
tab.textContent = league;
tab.onclick = async () => {
while (tablesContainer.firstChild) {
tablesContainer.removeChild(tablesContainer.firstChild);
}
const modalContent = document.getElementById("leagues-modal-content");
const loadingOverlay = document.createElement('div');
loadingOverlay.className = 'loading-overlay';
const spinner = document.createElement('div');
spinner.className = 'loader';
const loadingText = document.createElement('div');
loadingText.className = 'loading-text';
loadingText.textContent = 'Loading ロード中…';
loadingOverlay.appendChild(spinner);
loadingOverlay.appendChild(loadingText);
modalContent.appendChild(loadingOverlay);
loadingOverlay.style.display = 'flex';
const leagueIds = leagues[league];
const tables = await Promise.all(leagueIds.map((sid, index) =>
fetchLeagueTable(sid, leagueType, index + 1, country)
));
tables.sort((a, b) => a.divisionCount - b.divisionCount);
tables.forEach(data => {
if (data) {
const hr = document.createElement("hr");
const title = createLeagueTitle(league, data.divisionCount, leagueType, country, league);
tablesContainer.appendChild(hr);
tablesContainer.appendChild(title);
tablesContainer.appendChild(data.table);
}
});
loadingOverlay.style.display = 'none';
loadingOverlay.remove();
};
container.appendChild(tab);
});
return container;
}
async function fetchLeagueTable(sid, leagueType, divisionCount, country) {
try {
const response = await fetch(
`https://www.managerzone.com/ajax.php?p=league&type=${leagueType}&sid=${sid}&tid=${teamId}&sport=${sport}&sub=table`
);
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
const table = doc.querySelector(".nice_table");
if (!table) return null;
setUpTableLinks(table);
setUpHelpButton(table, sid, leagueType);
return {
table,
divisionCount,
country
};
} catch (error) {
console.error("Error fetching league table:", error);
return null;
}
}
function setUpTableLinks(table) {
const rows = table.querySelectorAll('tbody tr');
rows.forEach(row => {
const link = row.querySelector('a[href^="/?p=league&type="]');
if (link) {
const tid = link.href.match(/tid=(\d+)/);
if (tid) {
link.href = `/?p=team&tid=${tid[1]}`;
}
}
const helpButton = row.querySelector('.help_button');
if (helpButton) {
helpButton.style.pointerEvents = 'none';
helpButton.style.opacity = '0.5';
helpButton.style.cursor = 'default';
helpButton.onclick = (e) => {
e.preventDefault();
return false;
};
helpButton.href = 'javascript:void(0);';
}
});
}
function setUpHelpButton(table, sid, leagueType) {
const secondRow = table.querySelector("tbody tr:nth-child(2)");
if (!secondRow) return;
const helpButton = secondRow.querySelector(".help_button");
const teamLink = secondRow.querySelector("a[onclick*='purchaseChallenge']");
if (helpButton && teamLink) {
const tid = teamLink.getAttribute("onclick").split(",")[2].replace(/[ ';)]/g, "");
helpButton.removeAttribute("onclick");
helpButton.onclick = () => handleExtraLeagueData(sid, leagueType, tid);
}
}
function handleExtraLeagueData(sid, leagueType, tid) {
fetch(
`https://www.managerzone.com/ajax.php?p=extraLeague&sub=division_runner_ups&type=${leagueType}&sid=${sid}&tid=${tid}&sport=${sport}`
)
.then(response => response.text())
.then(html => {
const modal = document.createElement("div");
modal.id = "extra-league-data-modal";
modal.className = "leagues-modal";
const content = document.createElement("div");
content.className = "leagues-modal-content";
content.innerHTML = html;
modal.appendChild(content);
document.body.appendChild(modal);
modal.onclick = (event) => {
if (event.target === modal) modal.remove();
};
});
}
function createLeagueTitle(selectedLeague, divisionCount, type, country, tabName) {
const p = document.createElement("p");
if (!selectedLeague.startsWith("Division")) {
p.textContent = selectedLeague;
} else {
const theDivision = selectedLeague + "." + divisionCount;
p.textContent = theDivision.replace("Division", "div");
}
p.textContent += " " + type.charAt(0).toUpperCase() + type.slice(1);
if ((type === "senior" || type === "u18" || type === "u21" || type === "u23") && country !== "All") {
p.textContent += " " + country;
}
if (p.textContent.includes("All")) {
p.textContent = p.textContent.replace("All", "");
}
if (p.textContent.includes("_")) {
p.textContent = p.textContent.replace("_", " ");
}
if (type === "senior" && country === "All" && tabName === "Top Division") {
p.textContent += " " + Object.keys(seniorLeagues)[divisionCount - 1];
}
const tabNameEndsWithNumber = /\d$/.test(tabName);
if (!type.includes("world") && tabNameEndsWithNumber) {
const tabNameNumber = parseInt(tabName.slice(-1));
const match = RegExp(/\.\d+/).exec(p.textContent);
if (match) {
const number = parseInt(match[0].slice(1));
const divisor = Math.pow(3, tabNameNumber);
if (number > divisor) {
const replacement = number % divisor || divisor;
p.textContent = p.textContent.replace(/\.\d+/, `.${replacement}`);
}
}
}
return p;
}
function getLeagueTypeFromButtonId(id) {
if (id.includes("senior leagues")) return "senior";
if (id.includes("u18 world leagues")) return "u18_world";
if (id.includes("u21 world leagues")) return "u21_world";
if (id.includes("u23 world leagues")) return "u23_world";
if (id.includes("u18 leagues")) return "u18";
if (id.includes("u21 leagues")) return "u21";
if (id.includes("u23 leagues")) return "u23";
return "world";
}
function getLeaguesObjFromLeagueType(leagueType, country) {
switch (leagueType) {
case "senior":
return country === "All" ? getAllLeagues(seniorLeagues) : seniorLeagues[country];
case "world":
case "u18_world":
case "u21_world":
case "u23_world":
return worldLeagues.World;
case "u18":
case "u21":
case "u23":
return country === "All" ? getAllLeagues(uxxLeagues) : uxxLeagues[country];
default:
return {};
}
}
function getAllLeagues(leaguesObj) {
const allLeagues = {};
Object.entries(leaguesObj).forEach(([country, leagues]) => {
Object.entries(leagues).forEach(([league, ids]) => {
if (!allLeagues[league]) allLeagues[league] = [];
allLeagues[league].push(...ids);
});
});
return allLeagues;
}
function getCountries(leagueType) {
if (["world", "u18_world", "u21_world", "u23_world"].includes(leagueType)) {
return ["World"];
}
return Object.keys(leagueType === "senior" ? seniorLeagues : uxxLeagues);
}
function getSeniorLeagues() {
const soccerCountries = [
{ name: "Argentina", start: 16096 },
{ name: "Brazil", start: 26187 },
{ name: "China", start: 70847 },
{ name: "Germany", start: 12086 },
{ name: "Italy", start: 10625 },
{ name: "Netherlands", start: 15004 },
{ name: "Portugal", start: 17566 },
{ name: "Spain", start: 10746 },
{ name: "Poland", start: 13181 },
{ name: "Romania", start: 17929 },
{ name: "Sweden", start: 43 },
{ name: "Turkey", start: 20356 }
];
const hockeyCountries = [
{ name: "Brazil", start: 7900 },
{ name: "Sweden", start: 1 },
{ name: "Argentina", start: 2 },
{ name: "Poland", start: 23 },
{ name: "Portugal", start: 24 },
{ name: "Spain", start: 12 },
{ name: "Romania", start: 25 },
{ name: "Turkey", start: 27 },
{ name: "China", start: 13727 }
];
const countries = sport === "soccer" ? soccerCountries : hockeyCountries;
return countries.reduce((acc, { name, start }) => {
acc[name] = { "Top Division": [start] };
return acc;
}, {});
}
function getWorldLeaguesObj() {
const leagues = {};
let start = 1;
for (let i = 0; i <= 4; ++i) {
const divisionName = i === 0 ? "Top Series" : `Division ${i}`;
leagues[divisionName] = [];
const numLeagues = Math.pow(3, i);
for (let j = 0; j < numLeagues; ++j) {
leagues[divisionName].push(start++);
}
}
return leagues;
}
function getUxxLeagues() {
const soccerRegions = [
{ name: "Argentina", start: 1 },
{ name: "Brazil", start: 122 },
{ name: "Latin America, USA and Canada", start: 727 },
{ name: "Central Europe", start: 848 },
{ name: "Iberia", start: 969 },
{ name: "Mediterranean", start: 1090 },
{ name: "Northern Europe", start: 1211 },
{ name: "Poland", start: 243 },
{ name: "Romania", start: 364 },
{ name: "Sweden", start: 485 },
{ name: "Turkey", start: 606 },
{ name: "China/Asia/Africa", start: 1332 }
];
const hockeyRegions = [
{ name: "Northern Europe", start: 1 },
{ name: "Southern Europe", start: 122 },
{ name: "Rest of the World", start: 243 }
];
const regions = sport === "soccer" ? soccerRegions : hockeyRegions;
return regions.reduce((acc, region) => {
acc[region.name] = {
"Top Division": [region.start],
"Division 1": Array.from({ length: 3 }, (_, i) => region.start + i + 1),
"Division 2": Array.from({ length: 9 }, (_, i) => region.start + i + 4)
};
return acc;
}, {});
}
})();