// ==UserScript== // @name MZ Player Values // @namespace http://tampermonkey.net/ // @version 0.26 // @description Add Squad Value to some pages // @author z7z // @license MIT // @grant GM_addStyle // @grant GM_xmlhttpRequest // @connect self // @match https://www.managerzone.com/?p=players&sub=alt // @match https://www.managerzone.com/?p=players&sub=alt&tid=* // @match https://www.managerzone.com/?p=federations&sub=clash* // @match https://www.managerzone.com/?p=federations // @match https://www.managerzone.com/?p=federations&fid=* // @match https://www.managerzone.com/?p=match&sub=result&mid=* // @icon https://www.google.com/s2/favicons?sz=64&domain=managerzone.com // @downloadURL none // ==/UserScript== (function () { "use strict"; /* *********************** Styles ********************************** */ GM_addStyle(` table.squad-summary tbody td, table.squad-summary thead th { padding: 0.3em 0.5em; } .donut { width: 1.7em; height: 1.7em; margin-right: 5px; border-radius: 50%; text-align: center; font-size: 1.2em; padding: 3px; background-color: yellow; color: yellow; } .final-donut { border: rgb(213, 232, 44) solid 2px; color: inherit; padding:0; } .loading-donut { border-bottom-color: rgb(213, 232, 44); animation: 1.5s donut-spin infinite linear; } @keyframes donut-spin { to { transform: rotate(360deg); } } `); /* *********************** Utils ********************************** */ function getSportType(doc = document) { const zone = doc.querySelector("a#shortcut_link_thezone"); if (zone) { return zone.href.indexOf("hockey") > -1 ? "hockey" : "soccer"; } return "soccer"; } function isNationalTeam(teamTable) { const images = teamTable.getElementsByTagName("img"); if (images) { return [...images].some((img) => img.src.endsWith("mz.png")); } return false; } function getCurrency(doc) { const players = doc.getElementById("playerAltViewTable")?.querySelectorAll("tbody tr"); if (players && players.length > 0) { const parts = players[0].querySelector("td:nth-child(3)")?.innerText.split(" "); return parts[parts.length - 1]; } return ""; } function getNationalCurrency(doc) { // works for both domestic and foreign countries const playerNode = doc.getElementById("thePlayers_0")?.querySelector("table tbody tr:nth-child(6)"); if (playerNode) { const parts = playerNode.innerText.split(" "); return parts[parts.length - 1]; } return ""; } function extractTeamID(link) { const regex = /tid=(\d+)/; const match = regex.exec(link); return match ? match[1] : null; } function extractPlayerID(link) { const regex = /pid=(\d+)/; const match = regex.exec(link); return match ? match[1] : null; } function formatBigNumber(n, sep = " ") { const numberString = n.toString(); let formattedParts = []; for (let i = numberString.length - 1; i >= 0; i -= 3) { let part = numberString.substring(Math.max(i - 2, 0), i + 1); formattedParts.unshift(part); } return formattedParts.join(sep); } function getPlayers(doc, currency) { const playerNodes = doc.getElementById("playerAltViewTable")?.querySelectorAll("tr"); if (!playerNodes) { return []; } const players = []; for (const playerNode of [...playerNodes]) { const age = playerNode.querySelector("td:nth-child(5)")?.innerText.replace(/\s/g, ""); if (age) { const value = playerNode .querySelector("td:nth-child(3)") ?.innerText.replaceAll(currency, "") .replace(/\s/g, ""); const shirtNumber = playerNode.querySelector("td:nth-child(0)")?.innerText.replace(/\s/g, ""); const pid = playerNode.querySelector("a")?.href; players.push({ shirtNumber, age: parseInt(age, 10), value: parseInt(value, 10), id: extractPlayerID(pid), }); } } return players; } function getNumberOfFlags(infoTable) { const images = infoTable.getElementsByTagName("img"); return images ? [...images].filter((img) => img.src.indexOf("/flags/") > -1).length : 0; } function isDomesticPlayer(infoTable) { return getNumberOfFlags(infoTable) === 1; } function getNationalPlayers(doc, currency) { const players = []; const playerNodes = doc.querySelectorAll("div.playerContainer"); if (playerNodes) { for (const playerNode of [...playerNodes]) { const id = extractPlayerID(playerNode.querySelector("h2 a")?.href); const infoTable = playerNode.querySelector("div.dg_playerview_info table"); const age = infoTable.querySelector("tbody tr:nth-child(1) td strong").innerText; const selector = isDomesticPlayer(infoTable) ? "tbody tr:nth-child(5) td span" : "tbody tr:nth-child(6) td span"; const value = infoTable.querySelector(selector)?.innerText.replaceAll(currency, "").replace(/\s/g, ""); players.push({ age: parseInt(age, 10), value: parseInt(value, 10), id, }); } } return players; } /* *********************** Squad Summary ********************************** */ function getValueOfPlayers(players, count, ageLow = 0, ageHigh = 99) { const n = count === 0 ? players.length : count; return players .filter((player) => player.age <= ageHigh && player.age >= ageLow) .sort((a, b) => b.value - a.value) .slice(0, n) .map((player) => player.value) .reduce((a, b) => a + b, 0); } function getNumberOfPlayers(players, ageLow = 0, ageHigh = 99) { return players.filter((player) => player.age <= ageHigh && player.age >= ageLow).length; } function getSquadSummary(players, currency = "USD", sport = "soccer") { const rows = []; if (players) { if (sport === "hockey") { rows.push({ title: "All", count: players.length, all: getValueOfPlayers(players), top21: getValueOfPlayers(players, 21), }); rows.push({ title: "U23", count: getNumberOfPlayers(players, 0, 23), all: getValueOfPlayers(players, 0, 0, 23), top21: getValueOfPlayers(players, 21, 0, 23), }); rows.push({ title: "U21", count: getNumberOfPlayers(players, 0, 21), all: getValueOfPlayers(players, 0, 0, 21), top21: getValueOfPlayers(players, 21, 0, 21), }); rows.push({ title: "U18", count: getNumberOfPlayers(players, 0, 18), all: getValueOfPlayers(players, 0, 0, 18), top21: getValueOfPlayers(players, 21, 0, 18), }); } else { rows.push({ title: "All", count: players.length, all: getValueOfPlayers(players), top16: getValueOfPlayers(players, 16), top11: getValueOfPlayers(players, 11), }); rows.push({ title: "U23", count: getNumberOfPlayers(players, 0, 23), all: getValueOfPlayers(players, 0, 0, 23), top16: getValueOfPlayers(players, 16, 0, 23), top11: getValueOfPlayers(players, 11, 0, 23), }); rows.push({ title: "U21", count: getNumberOfPlayers(players, 0, 21), all: getValueOfPlayers(players, 0, 0, 21), top16: getValueOfPlayers(players, 16, 0, 21), top11: getValueOfPlayers(players, 11, 0, 21), }); rows.push({ title: "U18", count: getNumberOfPlayers(players, 0, 18), all: getValueOfPlayers(players, 0, 0, 18), top16: getValueOfPlayers(players, 16, 0, 18), top11: getValueOfPlayers(players, 11, 0, 18), }); } } return rows; } function createSquadTable(rows, currency = "USD", sport = "soccer") { const table = document.createElement("table"); table.classList.add("squad-summary"); const thead = document.createElement("thead"); table.appendChild(thead); const titleHeader = document.createElement("th"); thead.appendChild(titleHeader); titleHeader.innerText = "Group"; titleHeader.style.textAlign = "center"; titleHeader.style.textDecoration = "none"; const countHeader = document.createElement("th"); thead.appendChild(countHeader); countHeader.innerText = "Count"; countHeader.title = "Number of Players"; countHeader.style.textAlign = "center"; countHeader.style.textDecoration = "none"; const totalHeader = document.createElement("th"); thead.appendChild(totalHeader); totalHeader.innerHTML = "Total"; totalHeader.title = "Total Value of Players"; totalHeader.style.textAlign = "center"; totalHeader.style.textDecoration = "none"; if (sport === "soccer") { const top16Header = document.createElement("th"); thead.appendChild(top16Header); top16Header.innerHTML = "Top 16"; top16Header.title = "Value of Top 16 Players"; top16Header.style.textAlign = "center"; top16Header.style.textDecoration = "none"; const top11Header = document.createElement("th"); thead.appendChild(top11Header); top11Header.innerHTML = "Top 11"; top11Header.title = "Value of Top 11 Players"; top11Header.style.textAlign = "center"; top11Header.style.textDecoration = "none"; } else { const top21Header = document.createElement("th"); thead.appendChild(top21Header); top21Header.innerHTML = "Top 21"; top21Header.title = "Value of Top 21 Players"; top21Header.style.textAlign = "center"; top21Header.style.textDecoration = "none"; } const tbody = document.createElement("tbody"); table.appendChild(tbody); for (const row of rows) { const tr = document.createElement("tr"); tbody.appendChild(tr); const title = document.createElement("td"); title.innerHTML = `${row.title}`; tr.appendChild(title); const count = document.createElement("td"); count.innerHTML = `${row.count}`; count.style.textAlign = "center"; tr.appendChild(count); const all = document.createElement("td"); all.innerText = `${formatBigNumber(row.all)} ${currency}`; all.style.textAlign = "end"; tr.appendChild(all); if (sport === "soccer") { const top16 = document.createElement("td"); top16.innerText = `${formatBigNumber(row.top16)} ${currency}`; top16.style.textAlign = "end"; tr.appendChild(top16); const top11 = document.createElement("td"); top11.innerText = `${formatBigNumber(row.top11)} ${currency}`; top11.style.textAlign = "end"; tr.appendChild(top11); } else { const top21 = document.createElement("td"); tr.appendChild(top21); top21.innerText = `${formatBigNumber(row.top21)} ${currency}`; top21.style.textAlign = "end"; } } return table; } function injectToSquadSummaryPage() { const sport = getSportType(document); const currency = getCurrency(document); const players = getPlayers(document, currency); const summary = getSquadSummary(players, currency, sport); const table = createSquadTable(summary, currency, sport); table.classList.add("tablesorter", "hitlist", "marker", "hitlist-compact-list-included"); table.style.borderSpacing = 0; table.style.marginBottom = "10px"; table.align = "center"; const place = document.querySelector("table#playerAltViewTable"); if (place) { place.parentNode?.insertBefore(table, place); } } /* *********************** Clash ********************************** */ function createModal() { const modal = document.createElement("div"); document.body.appendChild(modal); modal.style.display = "none"; modal.style.position = "fixed"; modal.style.zIndex = "1"; modal.style.left = "0"; modal.style.top = "0"; modal.style.width = "100%"; modal.style.height = "100%"; modal.style.overflow = "auto"; modal.style.backgroundColor = "rgba(0, 0, 0, 0.4)"; modal.id = "squad-display-modal"; modal.onclick = () => { modal.style.display = "none"; }; const modalContent = document.createElement("div"); modal.appendChild(modalContent); modalContent.style.backgroundColor = "#fefefe"; modalContent.style.margin = "15% auto"; modalContent.style.padding = "20px"; modalContent.style.border = "1px solid #888"; modalContent.style.width = "30%"; const divContent = document.createElement("div"); modalContent.appendChild(divContent); divContent.id = "squad-display-modal-content"; } function displayOnModal(url) { const divContent = document.getElementById("squad-display-modal-content"); divContent.innerHTML = "loading..."; const modal = document.getElementById("squad-display-modal"); modal.style.display = "block"; GM_xmlhttpRequest({ method: "GET", url, onload: function (resp) { const parser = new DOMParser(); const doc = parser.parseFromString(resp.responseText, "text/html"); const sport = getSportType(doc); const currency = getCurrency(doc); const players = getPlayers(doc, currency); const summary = getSquadSummary(players, currency, sport); const table = createSquadTable(summary, currency, sport); table.classList.add("tablesorter", "hitlist", "marker", "hitlist-compact-list-included"); table.style.width = "auto"; table.align = "center"; const target = document.getElementById("squad-display-modal-content"); target.replaceChildren(table); }, }); } function getSquadSummaryLink(url) { const tid = extractTeamID(url); return `https://www.managerzone.com/?p=players&sub=alt&tid=${tid}`; } function getTopPlyers(doc) { const currency = getCurrency(doc); const players = getPlayers(doc, currency); const sport = getSportType(doc); const count = sport === "soccer" ? 11 : 21; return players ? getValueOfPlayers(players, count) : 0; } function calculateRankOfTeams() { const tbody = document.querySelector("div.panel-2 table tbody"); const rows = tbody.querySelectorAll("tr"); const teams = document.querySelectorAll("a.team-name"); const finals = []; let i = 0; for (const team of teams) { const url = getSquadSummaryLink(team.href); finals.push({ target: team, row: rows[i], url, values: 0, done: false, currency: "", }); i++; GM_xmlhttpRequest({ method: "GET", url, context: finals, onload: function (resp) { const parser = new DOMParser(); const doc = parser.parseFromString(resp.responseText, "text/html"); const currency = getCurrency(doc); const values = getTopPlyers(doc); const fin = resp.context?.find((p) => resp.finalUrl === p.url); if (fin) { fin.values = values; fin.done = true; fin.currency = currency; } }, }); } let timeout = 16000; const step = 1000; let interval = setInterval(() => { if (finals.every((a) => a.done)) { clearInterval(interval); finals.sort((a, b) => b.values - a.values); let rank = 0; for (const team of finals) { rank++; team.row.className = rank % 2 ? "odd" : "even"; const target = team.row.querySelector("button.donut.rank"); target.classList.remove("loading-donut"); target.classList.add("final-donut"); target.innerText = `${rank}`; const value = team.row.querySelector("td.value"); value.innerText = `${formatBigNumber(team.values, ",")} ${team.currency}`; } const newOrder = finals.map((t) => t.row); tbody.replaceChildren(...newOrder); } else { timeout -= step; if (timeout < 0) { clearInterval(interval); for (const team of finals) { const target = team.row.querySelector("button.donut.rank"); target.classList.remove("loading-donut"); target.classList.add("final-donut"); target.innerText = `-`; const value = team.row.querySelector("td.value"); value.innerText = `N/A`; } } } }, step); } function addRankView(target) { const value = document.createElement("td"); value.innerText = ""; value.classList.add("value"); value.style.textAlign = "right"; target.insertBefore(value, target.firstChild); const rank = document.createElement("td"); const button = document.createElement("button"); button.innerText = "_"; button.classList.add("donut", "loading-donut", "rank"); button.title = "Click to see squad summary"; rank.appendChild(button); target.insertBefore(rank, target.firstChild); const name = target.querySelector("a.team-name"); const url = getSquadSummaryLink(name.href); button.onclick = () => { displayOnModal(url); }; } function injectToClashPage() { createModal(); const table = document.querySelector("table.hitlist.challenges-list"); const headers = table.querySelector("thead tr"); const value = document.createElement("th"); value.style.textAlign = "right"; value.innerText = "Values"; value.style.width = "15%"; headers.insertBefore(value, headers.firstChild); const rank = document.createElement("th"); rank.innerText = "Rank"; rank.style.width = "5%"; headers.insertBefore(rank, headers.firstChild); const teams = table.querySelectorAll("tbody tr"); for (const team of teams) { addRankView(team); } calculateRankOfTeams(); } /* *********************** Federation Page ********************************** */ function fetchTopPlayers(context, tid) { const url = `https://www.managerzone.com/?p=players&sub=alt&tid=${tid}`; GM_xmlhttpRequest({ method: "GET", url, context, onload: function (resp) { const parser = new DOMParser(); const doc = parser.parseFromString(resp.responseText, "text/html"); const team = resp.context.teams.find((t) => t.username === resp.context.username); team.currency = getCurrency(doc); team.values = getTopPlyers(doc); const name = document.createElement("div"); name.style.color = "blue"; name.style.width = "100%"; name.style.marginTop = "3px"; name.title = team.name; const teamName = team.name.length > 20 ? team.name.substring(0, 16) + " >>>" : team.name; name.innerHTML = `Team: ${teamName}`; team.node.querySelector("td").appendChild(name); const value = document.createElement("div"); value.style.color = "blue"; value.style.width = "100%"; value.style.marginTop = "3px"; const count = resp.context.sport === "soccer" ? 11 : 21; value.innerHTML = `Top${count}: ` + `${formatBigNumber(team.values, ",")} ${team.currency}`; team.node.querySelector("td").appendChild(value); team.done = true; }, }); } async function fetchTeamValue(sport, teams, username) { const url = `https://www.managerzone.com/xml/manager_data.php?username=${username}`; GM_xmlhttpRequest({ method: "GET", url: url, context: { sport, teams, username }, onload: function (resp) { const parser = new DOMParser(); const doc = parser.parseFromString(resp.responseText, "text/xml"); const teamId = doc.querySelector(`Team[sport="${resp.context.sport}"]`).getAttribute("teamId"); const name = doc.querySelector(`Team[sport="${resp.context.sport}"]`).getAttribute("teamName"); resp.context.teams.find((t) => t.username === resp.context.username).name = name; fetchTopPlayers(resp.context, teamId); }, }); } function getUsername(node) { return node.querySelector("a").innerText; } function getTableHeader() { const thead = document.querySelector("#federation_clash_members_list thead td"); return thead.innerText; } function setTableHeader(text) { const thead = document.querySelector("#federation_clash_members_list thead td"); thead.innerText = text; } function sortFederationTeamsByTopPlayers() { const tbody = document.querySelector("#federation_clash_members_list tbody"); const sport = getSportType(); const teams = []; for (const child of tbody.children) { const username = getUsername(child); teams.push({ node: child, username, name, teamId: "", values: 0, currency: "", done: false, }); fetchTeamValue(sport, teams, username); } let timeout = 60000; const step = 1000; const tableHeader = getTableHeader(); let dots = 0; let interval = setInterval(() => { if (teams.every((t) => t.done)) { clearInterval(interval); teams.sort((a, b) => b.values - a.values); const newOrder = teams.map((t) => t.node); let rank = 0; for (const row of newOrder) { rank++; row.className = rank % 2 ? "odd" : "even"; } tbody.replaceChildren(...newOrder); setTableHeader(tableHeader + " ▼"); let totalValue = 0; for (const team of teams) { totalValue += team.values; } const total = document.createElement("tr"); total.style.color = "blue"; total.style.width = "100%"; total.style.marginTop = "3px"; total.innerHTML = `