// ==UserScript==
// @name MZ - Multiple League Standings in a Single View
// @namespace douglaskampl
// @version 3.8
// @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 CONSTANTS = {
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: 'World (Asia, Oceania and 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 }
]
}
},
LEAGUE_TYPES: {
SENIOR: 'senior',
U18: 'u18',
U21: 'u21',
U23: 'u23',
WORLD: 'world',
U18_WORLD: 'u18_world',
U21_WORLD: 'u21_world',
U23_WORLD: 'u23_world'
},
DIVISION: {
NAMES: {
TOP: 'Top Division',
TOP_SERIES: 'Top Series'
},
STRUCTURE: {
BASE_DIVISIONS: 3,
MAX_LEVEL: 4
}
},
SELECTORS: {
TEAM_INFO: '#infoAboutTeam',
STADIUM_WRAPPER: '#team-stadium-wrapper',
SHORTCUT_LINK: '#shortcut_link_thezone'
},
TEXTS: {
TOGGLE_UP: 'UP 上',
TOGGLE_DOWN: 'DOWN 下',
LOADING: 'Loading ロード中…'
},
BUTTON_NAMES: [
'Senior Leagues',
'U18 Leagues',
'U21 Leagues',
'U23 Leagues',
'Senior World Leagues',
'U18 World Leagues',
'U21 World Leagues',
'U23 World Leagues'
]
};
class LeagueManager {
constructor() {
const shortcutLink = document.querySelector(CONSTANTS.SELECTORS.SHORTCUT_LINK);
this.sport = new URL(shortcutLink.href).searchParams.get('sport');
const teamInfo = document.querySelector(CONSTANTS.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' ? CONSTANTS.REGIONS.SOCCER.COUNTRIES : CONSTANTS.REGIONS.HOCKEY.COUNTRIES;
return countries.reduce((acc, { name, start }) => {
acc[name] = { [CONSTANTS.DIVISION.NAMES.TOP]: [start] };
return acc;
}, {});
}
getWorldLeaguesObj() {
const leagues = {};
let start = 1;
for (let i = 0; i <= CONSTANTS.DIVISION.STRUCTURE.MAX_LEVEL; i++) {
const divisionName = i === 0 ? CONSTANTS.DIVISION.NAMES.TOP_SERIES : `Division ${i}`;
leagues[divisionName] = [];
const numLeagues = Math.pow(CONSTANTS.DIVISION.STRUCTURE.BASE_DIVISIONS, i);
for (let j = 0; j < numLeagues; j++) {
leagues[divisionName].push(start++);
}
}
return leagues;
}
getUxxLeagues() {
const regions = this.sport === 'soccer' ? CONSTANTS.REGIONS.SOCCER.UXX_REGIONS : CONSTANTS.REGIONS.HOCKEY.UXX_REGIONS;
const obj = {};
regions.forEach(region => {
obj[region.name] = {
[CONSTANTS.DIVISION.NAMES.TOP]: [region.start],
'Division 1': Array.from({ length: CONSTANTS.DIVISION.STRUCTURE.BASE_DIVISIONS }, (_, i) => region.start + i + 1),
'Division 2': Array.from({ length: Math.pow(CONSTANTS.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 CONSTANTS.LEAGUE_TYPES.SENIOR;
if (id.includes('u18 world leagues')) return CONSTANTS.LEAGUE_TYPES.U18_WORLD;
if (id.includes('u21 world leagues')) return CONSTANTS.LEAGUE_TYPES.U21_WORLD;
if (id.includes('u23 world leagues')) return CONSTANTS.LEAGUE_TYPES.U23_WORLD;
if (id.includes('u18 leagues')) return CONSTANTS.LEAGUE_TYPES.U18;
if (id.includes('u21 leagues')) return CONSTANTS.LEAGUE_TYPES.U21;
if (id.includes('u23 leagues')) return CONSTANTS.LEAGUE_TYPES.U23;
return CONSTANTS.LEAGUE_TYPES.WORLD;
}
getLeaguesObjFromLeagueType(leagueType, country) {
switch (leagueType) {
case CONSTANTS.LEAGUE_TYPES.SENIOR:
return country === 'All' ? this.getAllLeagues(this.seniorLeagues) : this.seniorLeagues[country];
case CONSTANTS.LEAGUE_TYPES.WORLD:
case CONSTANTS.LEAGUE_TYPES.U18_WORLD:
case CONSTANTS.LEAGUE_TYPES.U21_WORLD:
case CONSTANTS.LEAGUE_TYPES.U23_WORLD:
return this.worldLeagues.World;
case CONSTANTS.LEAGUE_TYPES.U18:
case CONSTANTS.LEAGUE_TYPES.U21:
case CONSTANTS.LEAGUE_TYPES.U23:
return country === 'All' ? this.getAllLeagues(this.uxxLeagues) : this.uxxLeagues[country];
default:
return {};
}
}
getCountries(leagueType) {
if (
leagueType === CONSTANTS.LEAGUE_TYPES.WORLD ||
leagueType === CONSTANTS.LEAGUE_TYPES.U18_WORLD ||
leagueType === CONSTANTS.LEAGUE_TYPES.U21_WORLD ||
leagueType === CONSTANTS.LEAGUE_TYPES.U23_WORLD
) {
return ['World'];
}
if (leagueType === CONSTANTS.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(CONSTANTS.SELECTORS.STADIUM_WRAPPER).appendChild(mainContainer);
}
createToggleButton() {
const btn = document.createElement('button');
btn.id = 'league-toggle-button';
btn.textContent = CONSTANTS.TEXTS.TOGGLE_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.TEXTS.TOGGLE_UP;
} else {
btn.classList.remove('fade-in');
btn.classList.add('fade-out');
setTimeout(() => {
btn.style.display = 'none';
}, 200);
toggleBtn.textContent = CONSTANTS.TEXTS.TOGGLE_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 !== CONSTANTS.LEAGUE_TYPES.WORLD &&
leagueType !== CONSTANTS.LEAGUE_TYPES.U18_WORLD &&
leagueType !== CONSTANTS.LEAGUE_TYPES.U21_WORLD &&
leagueType !== CONSTANTS.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 leagueTypeFromTitle = this.leagueManager.getLeagueTypeFromButtonId('league-button-' + document.getElementById('leagues-modal-title').textContent.toLowerCase());
const newTabs = this.createTabContainer(leagueTypeFromTitle, 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.TEXTS.LOADING;
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;
}
let divisionCount = index + 1;
if (league === 'Division 1') {
divisionCount = (index % 3) + 1;
} else if (league === 'Division 2') {
divisionCount = (index % 9) + 1;
}
return this.fetchLeagueTable(sid, leagueType, divisionCount, league, region);
})
);
tables.forEach(data => {
if (data) {
const hr = document.createElement('hr');
const title = this.createLeagueTitle(league, data.divisionCount, leagueType, data.region, data.sid);
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,
sid
};
} catch (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, sid) {
const p = document.createElement('p');
p.classList.add('league-table-title');
let leagueName;
if (!selectedLeague.startsWith('Division')) {
leagueName = selectedLeague;
} else {
const theDivision = selectedLeague + '.' + divisionCount;
leagueName = theDivision.replace('Division', 'div');
}
let typeName = leagueType.charAt(0).toUpperCase() + leagueType.slice(1);
typeName = typeName.replace('_', ' ');
let finalTitle = leagueName + ' ' + typeName;
if (region && region !== 'World') {
finalTitle += ' ' + region;
}
const a = document.createElement('a');
a.textContent = finalTitle;
a.href = `https://www.managerzone.com/?p=league&type=${leagueType}&sid=${sid}`;
a.target = '_blank';
p.appendChild(a);
return p;
}
}
const infoAboutTeam = document.querySelector(CONSTANTS.SELECTORS.TEAM_INFO);
const teamStadiumWrapper = document.querySelector(CONSTANTS.SELECTORS.STADIUM_WRAPPER);
if (infoAboutTeam && teamStadiumWrapper) {
const leagueManager = new LeagueManager();
const uiManager = new UIManager(leagueManager);
uiManager.initializeInterface();
}
})();