您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Displays leagues and world leagues, grouped by div and/or region, in a single view
// ==UserScript== // @name MZ - Multiple League Standings in a Single View // @namespace douglaskampl // @version 3.9 // @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 leagueStandingsStyles https://br18.org/mz/userscript/other/sLeagueStandings.css // @run-at document-idle // @license MIT // ==/UserScript== (function () { 'use strict'; GM_addStyle(GM_getResourceText('leagueStandingsStyles')); 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(); } })();