// ==UserScript==
// @name MZ - Multiple League Standings in a Single View
// @namespace douglaskampl
// @version 3.6
// @description Displays leagues and world leagues, grouped by div and/or region, 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
// @grant GM_getResourceText
// @resource sLeagueStandingsStyles https://u18mz.vercel.app/mz/userscript/other/sLeagueStandings.css
// @run-at document-idle
// @license MIT
// ==/UserScript==
(function () {
"use strict";
GM_addStyle(GM_getResourceText("sLeagueStandingsStyles"));
const UI = {
TEXTS: {
TOGGLE_UP: "UP 上",
TOGGLE_DOWN: "DOWN 下",
LOADING: "Loading ロード中…"
},
SELECTORS: {
TEAM_INFO: "#infoAboutTeam",
STADIUM_WRAPPER: "#team-stadium-wrapper",
SHORTCUT_LINK: "#shortcut_link_thezone"
}
};
const LEAGUE_TYPES = {
SENIOR: "senior",
U18: "u18",
U21: "u21",
U23: "u23",
WORLD: "world",
U18_WORLD: "u18_world",
U21_WORLD: "u21_world",
U23_WORLD: "u23_world"
};
const DIVISION = {
NAMES: {
TOP: "Top Division",
TOP_SERIES: "Top Series"
},
STRUCTURE: {
BASE_DIVISIONS: 3,
MAX_LEVEL: 4
}
};
const REGIONS = {
SOCCER: {
COUNTRIES: [
{ 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 }
],
UXX_REGIONS: [
{ 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 }
]
},
HOCKEY: {
COUNTRIES: [
{ 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 }
],
UXX_REGIONS: [
{ name: "Northern Europe", start: 1 },
{ name: "Southern Europe", start: 122 },
{ name: "Rest of the World", start: 243 }
]
}
};
const CONSTANTS = {
BUTTON_NAMES: [
"Senior Leagues",
"U18 Leagues",
"U21 Leagues",
"U23 Leagues",
"Senior World Leagues",
"U18 World Leagues",
"U21 World Leagues",
"U23 World Leagues"
],
TOGGLE_TEXT_DOWN: UI.TEXTS.TOGGLE_DOWN,
TOGGLE_TEXT_UP: UI.TEXTS.TOGGLE_UP,
LOADING_TEXT: UI.TEXTS.LOADING
};
class LeagueManager {
constructor() {
const shortcutLink = document.querySelector(UI.SELECTORS.SHORTCUT_LINK);
this.sport = new URL(shortcutLink.href).searchParams.get("sport");
const teamInfo = document.querySelector(UI.SELECTORS.TEAM_INFO);
this.teamId = RegExp(/\((\d+)\)/).exec(teamInfo.querySelector("dd").textContent)[1];
this.seniorLeagues = this.getSeniorLeagues();
this.worldLeagues = { World: this.getWorldLeaguesObj() };
this.uxxLeagues = this.getUxxLeagues();
}
getSeniorLeagues() {
const countries = this.sport === "soccer" ? REGIONS.SOCCER.COUNTRIES : REGIONS.HOCKEY.COUNTRIES;
return countries.reduce((acc, { name, start }) => {
acc[name] = { [DIVISION.NAMES.TOP]: [start] };
return acc;
}, {});
}
getWorldLeaguesObj() {
const leagues = {};
let start = 1;
for (let i = 0; i <= DIVISION.STRUCTURE.MAX_LEVEL; i++) {
const divisionName = i === 0 ? DIVISION.NAMES.TOP_SERIES : `Division ${i}`;
leagues[divisionName] = [];
const numLeagues = Math.pow(DIVISION.STRUCTURE.BASE_DIVISIONS, i);
for (let j = 0; j < numLeagues; j++) {
leagues[divisionName].push(start++);
}
}
return leagues;
}
getUxxLeagues() {
const regions = this.sport === "soccer" ? REGIONS.SOCCER.UXX_REGIONS : REGIONS.HOCKEY.UXX_REGIONS;
const obj = {};
regions.forEach(region => {
obj[region.name] = {
[DIVISION.NAMES.TOP]: [region.start],
"Division 1": Array.from({ length: DIVISION.STRUCTURE.BASE_DIVISIONS }, (_, i) => region.start + i + 1),
"Division 2": Array.from(
{ length: Math.pow(DIVISION.STRUCTURE.BASE_DIVISIONS, 2) },
(_, i) => region.start + i + 4
)
};
});
return obj;
}
getAllLeagues(leaguesObj) {
const allLeagues = {};
Object.entries(leaguesObj).forEach(([country, leagues]) => {
Object.entries(leagues).forEach(([leagueName, ids]) => {
if (!allLeagues[leagueName]) allLeagues[leagueName] = [];
ids.forEach((id) => {
allLeagues[leagueName].push({ sid: id, region: country });
});
});
});
return allLeagues;
}
getLeagueTypeFromButtonId(id) {
if (id.includes("senior leagues")) return LEAGUE_TYPES.SENIOR;
if (id.includes("u18 world leagues")) return LEAGUE_TYPES.U18_WORLD;
if (id.includes("u21 world leagues")) return LEAGUE_TYPES.U21_WORLD;
if (id.includes("u23 world leagues")) return LEAGUE_TYPES.U23_WORLD;
if (id.includes("u18 leagues")) return LEAGUE_TYPES.U18;
if (id.includes("u21 leagues")) return LEAGUE_TYPES.U21;
if (id.includes("u23 leagues")) return LEAGUE_TYPES.U23;
return LEAGUE_TYPES.WORLD;
}
getLeaguesObjFromLeagueType(leagueType, country) {
switch (leagueType) {
case LEAGUE_TYPES.SENIOR:
return country === "All" ? this.getAllLeagues(this.seniorLeagues) : this.seniorLeagues[country];
case LEAGUE_TYPES.WORLD:
case LEAGUE_TYPES.U18_WORLD:
case LEAGUE_TYPES.U21_WORLD:
case LEAGUE_TYPES.U23_WORLD:
return this.worldLeagues.World;
case LEAGUE_TYPES.U18:
case LEAGUE_TYPES.U21:
case LEAGUE_TYPES.U23:
return country === "All" ? this.getAllLeagues(this.uxxLeagues) : this.uxxLeagues[country];
default:
return {};
}
}
getCountries(leagueType) {
if (
leagueType === LEAGUE_TYPES.WORLD ||
leagueType === LEAGUE_TYPES.U18_WORLD ||
leagueType === LEAGUE_TYPES.U21_WORLD ||
leagueType === LEAGUE_TYPES.U23_WORLD
) {
return ["World"];
}
if (leagueType === LEAGUE_TYPES.SENIOR) {
return Object.keys(this.seniorLeagues);
}
return Object.keys(this.uxxLeagues);
}
}
class UIManager {
constructor(leagueManager) {
this.leagueManager = leagueManager;
}
initializeInterface() {
const mainContainer = document.createElement("div");
mainContainer.id = "league-buttons-container";
const toggleBtn = this.createToggleButton();
toggleBtn.onclick = this.toggleLeagueButtons;
CONSTANTS.BUTTON_NAMES.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 = this.createLeaguesModal("leagues-modal", btn);
document.body.appendChild(leaguesModal);
};
mainContainer.appendChild(btn);
});
mainContainer.appendChild(toggleBtn);
document.querySelector(UI.SELECTORS.STADIUM_WRAPPER).appendChild(mainContainer);
}
createToggleButton() {
const btn = document.createElement("button");
btn.id = "league-toggle-button";
btn.textContent = CONSTANTS.TOGGLE_TEXT_DOWN;
return btn;
}
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 = CONSTANTS.TOGGLE_TEXT_UP;
} else {
btn.classList.remove("fade-in");
btn.classList.add("fade-out");
setTimeout(() => {
btn.style.display = "none";
}, 200);
toggleBtn.textContent = CONSTANTS.TOGGLE_TEXT_DOWN;
}
});
}
createLeaguesModal(modalId, button) {
const leagueType = this.leagueManager.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 = this.createCountryDropdown(leagueType);
content.appendChild(countryDropdown);
const tabContainer = this.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;
}
createCountryDropdown(leagueType) {
const dropdown = document.createElement("select");
dropdown.id = "country-dropdown";
if (
leagueType !== LEAGUE_TYPES.WORLD &&
leagueType !== LEAGUE_TYPES.U18_WORLD &&
leagueType !== LEAGUE_TYPES.U21_WORLD &&
leagueType !== LEAGUE_TYPES.U23_WORLD
) {
const allOption = document.createElement("option");
allOption.value = "All";
allOption.text = "All";
dropdown.appendChild(allOption);
}
const countries = this.leagueManager.getCountries(leagueType);
countries.forEach(country => {
const option = document.createElement("option");
option.value = country;
option.text = country;
dropdown.appendChild(option);
});
dropdown.onchange = () => {
const tablesContainer = document.getElementById("league-tables-container");
const tabs = document.getElementById("league-tabs");
while (tabs.firstChild) {
tabs.removeChild(tabs.firstChild);
}
while (tablesContainer.firstChild) {
tablesContainer.removeChild(tablesContainer.firstChild);
}
const newTabs = this.createTabContainer(leagueType, dropdown.value, tablesContainer);
tabs.parentNode.replaceChild(newTabs, tabs);
if (newTabs.firstChild) {
newTabs.firstChild.click();
}
};
return dropdown;
}
createTabContainer(leagueType, country, tablesContainer) {
const container = document.createElement("div");
container.id = "league-tabs";
const leagues = this.leagueManager.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 = CONSTANTS.LOADING_TEXT;
loadingOverlay.appendChild(spinner);
loadingOverlay.appendChild(loadingText);
modalContent.appendChild(loadingOverlay);
loadingOverlay.style.display = "flex";
const leagueEntries = leagues[league];
const tables = await Promise.all(
leagueEntries.map((entry, index) => {
let sid, region;
if (typeof entry === "object") {
sid = entry.sid;
region = entry.region;
} else {
sid = entry;
region = country;
}
return this.fetchLeagueTable(sid, leagueType, index + 1, league, region);
})
);
tables.sort((a, b) => a.divisionCount - b.divisionCount);
tables.forEach(data => {
if (data) {
const hr = document.createElement("hr");
const title = this.createLeagueTitle(league, data.divisionCount, leagueType, data.region, league);
tablesContainer.appendChild(hr);
tablesContainer.appendChild(title);
tablesContainer.appendChild(data.table);
}
});
loadingOverlay.style.display = "none";
loadingOverlay.remove();
};
container.appendChild(tab);
});
return container;
}
async fetchLeagueTable(sid, leagueType, divisionCount, tabName, region) {
try {
const response = await fetch(
`https://www.managerzone.com/ajax.php?p=league&type=${leagueType}&sid=${sid}&tid=${this.leagueManager.teamId}&sport=${this.leagueManager.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;
this.setUpTableLinks(table);
this.setUpHelpButton(table, sid, leagueType);
return {
table,
divisionCount,
region
};
} catch (error) {
console.error("Error fetching league table:", error);
return null;
}
}
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);";
}
});
}
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 = () => this.handleExtraLeagueData(sid, leagueType, tid);
}
}
async handleExtraLeagueData(sid, leagueType, tid) {
const response = await fetch(
`https://www.managerzone.com/ajax.php?p=extraLeague&sub=division_runner_ups&type=${leagueType}&sid=${sid}&tid=${tid}&sport=${this.leagueManager.sport}`
);
const html = await response.text();
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();
};
}
createLeagueTitle(selectedLeague, divisionCount, leagueType, region) {
const p = document.createElement("p");
p.classList.add("league-table-title");
if (!selectedLeague.startsWith("Division")) {
p.textContent = selectedLeague;
} else {
const theDivision = selectedLeague + "." + divisionCount;
p.textContent = theDivision.replace("Division", "div");
}
p.textContent += " " + leagueType.charAt(0).toUpperCase() + leagueType.slice(1);
if (region && region !== "World") {
p.textContent += " " + region;
}
if (p.textContent.includes("_")) {
p.textContent = p.textContent.replace("_", " ");
}
return p;
}
}
const infoAboutTeam = document.querySelector(UI.SELECTORS.TEAM_INFO);
const teamStadiumWrapper = document.querySelector(UI.SELECTORS.STADIUM_WRAPPER);
if (infoAboutTeam && teamStadiumWrapper) {
const leagueManager = new LeagueManager();
const uiManager = new UIManager(leagueManager);
uiManager.initializeInterface();
}
})();