// ==UserScript== // @name MZ Player Values // @namespace http://tampermonkey.net/ // @version 0.10 // @description Add a table to show squad value in squad summary tab // @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=* // @icon https://www.google.com/s2/favicons?sz=64&domain=managerzone.com // @downloadURL none // ==/UserScript== (function () { "use strict"; /* *********************** Styles ********************************** */ GM_addStyle(` .donut { width: 1.7em; height: 1.7em; margin-left: 5px; border-radius: 50%; text-align: center; font-weigth = bold; 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); } } `); /* *********************** Squad Summary ********************************** */ function formatBigNumber(n, sep = " ") { let 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 createSquadTable(rows, currency) { const table = document.createElement("table"); table.classList.add("tablesorter", "hitlist", "marker", "hitlist-compact-list-included"); table.width = "30%"; table.cellSpacing = "1px"; table.cellPadding = "3px"; table.border = "0"; table.align = "center"; const titleHeader = document.createElement("th"); titleHeader.align = "center"; titleHeader.classList.add("header"); titleHeader.innerText = "Group"; const valueHeader = document.createElement("th"); valueHeader.align = "center"; valueHeader.classList.add("header"); valueHeader.innerHTML = "Values"; const thead = document.createElement("thead"); thead.appendChild(titleHeader); thead.appendChild(valueHeader); table.appendChild(thead); const tbody = document.createElement("tbody"); for (const row of rows) { const tr = document.createElement("tr"); const title = document.createElement("td"); title.innerHTML = `${row.title}`; const value = document.createElement("td"); value.innerText = `${formatBigNumber(row.value)} ${currency}`; value.style.textAlign = "end"; value.width = "e"; tr.appendChild(title); tr.appendChild(value); tbody.appendChild(tr); } table.appendChild(tbody); const info = document.createElement("div"); info.appendChild(table); info.style = "margin: 10px 0px"; return info; } function getCurrency(doc) { const playerNode = doc.getElementById("playerAltViewTable")?.querySelectorAll("tr"); if (playerNode && playerNode.length > 1) { const valueText = playerNode[1].querySelector("td:nth-child(3)")?.innerText; const parts = valueText?.split(" "); return parts[parts.length - 1]; } return ""; } function getPlayers(doc, currency) { const players = []; const playerNodes = doc.getElementById("playerAltViewTable")?.querySelectorAll("tr"); 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, ""); players.push({ shirtNumber, age: parseInt(age, 10), value: parseInt(value, 10), }); } } return players; } function getTotal(players) { const values = players.map((player) => player.value); return values.reduce((a, b) => a + b, 0); } function getTopPlayers(players, count, ageLow = 0, ageHigh = 99) { return players .filter((player) => player.age <= ageHigh && player.age >= ageLow) .sort((a, b) => b.value - a.value) .slice(0, count) .map((player) => player.value) .reduce((a, b) => a + b, 0); } function createSquadSummary(doc) { const currency = getCurrency(doc); const rows = []; const players = getPlayers(doc, currency); if (players) { rows.push({ title: "All", value: getTotal(players), }); rows.push({ title: "Top 16 - All", value: getTopPlayers(players, 16), }); rows.push({ title: "Top 11 - All", value: getTopPlayers(players, 11), }); rows.push({ title: "Top 16 - U23", value: getTopPlayers(players, 16, 0, 23), }); rows.push({ title: "Top 11 - U23", value: getTopPlayers(players, 11, 0, 23), }); rows.push({ title: "Top 16 - U21", value: getTopPlayers(players, 16, 0, 21), }); rows.push({ title: "Top 11 - U21", value: getTopPlayers(players, 11, 0, 21), }); rows.push({ title: "Top 16 - U18", value: getTopPlayers(players, 16, 0, 18), }); rows.push({ title: "Top 11 - U18", value: getTopPlayers(players, 11, 0, 18), }); } return createSquadTable(rows, currency); } /* *********************** Clash ********************************** */ function createModal() { const modalContent = document.createElement("div"); modalContent.style.backgroundColor = "#fefefe"; modalContent.style.margin = "15% auto"; modalContent.style.padding = "20px"; modalContent.style.border = "1px solid #888"; modalContent.style.width = "15%"; const divContent = document.createElement("div"); divContent.id = "squad-display-modal-content"; modalContent.appendChild(divContent); const modal = document.createElement("div"); 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.appendChild(modalContent); modal.onclick = () => { modal.style.display = "none"; }; document.body.appendChild(modal); } function extractTeamID(link) { let regex = /tid=(\d+)/; let match = regex.exec(link); if (match) { return match[1]; } else { return null; } } function displayOnModal(url) { const modal = document.getElementById("squad-display-modal"); const divContent = document.getElementById("squad-display-modal-content"); divContent.innerHTML = "loading..."; 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 content = createSquadSummary(doc); divContent.innerHTML = content.innerHTML; }, }); } function getSquadSummaryLink(url) { const tid = extractTeamID(url); return `https://www.managerzone.com/?p=players&sub=alt&tid=${tid}`; } function getTopEleven(doc) { const currency = getCurrency(doc); const rows = []; const players = getPlayers(doc, currency); return players ? getTopPlayers(players, 11) : 0; } function calculateRankOfTeams(teams) { const finals = []; for (const team of teams) { const url = getSquadSummaryLink(team.href); finals.push({ target: team, url, values: 0, done: false, }); GM_xmlhttpRequest({ method: "GET", url, onload: function (resp) { const parser = new DOMParser(); const doc = parser.parseFromString(resp.responseText, "text/html"); const values = getTopEleven(doc); const fin = finals.find((p) => resp.finalUrl === p.url); fin.values = values; fin.done = true; }, }); } 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++; const target = team.target.parentNode.querySelector("button.donut"); target.classList.remove("loading-donut"); target.classList.add("final-donut"); target.innerText = `${rank}`; } } else { timeout -= step; if (timeout < 0) { clearInterval(interval); for (const team of finals) { const target = team.target.parentNode.querySelector("button.donut"); target.classList.remove("loading-donut"); target.classList.add("final-donut"); target.innerText = `-`; } } } }, step); } function addSquadButton(target) { const url = getSquadSummaryLink(target.href); const button = document.createElement("button"); button.classList.add("donut", "final-donut"); button.innerText = `S`; button.style.color = "inherit"; target.parentNode.appendChild(button); button.onclick = () => { displayOnModal(url); }; } function addRankView(target) { const url = getSquadSummaryLink(target.href); const rank = document.createElement("button"); rank.innerText = "_"; rank.classList.add("donut", "loading-donut"); target.parentNode.appendChild(rank); } function addSquadButtonsToClashPage() { const teams = document.querySelectorAll("a.team-name"); for (const team of teams) { addRankView(team); addSquadButton(team); } calculateRankOfTeams(teams); } /* *********************** Sort ********************************** */ function fetchTopEleven(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); const currency = getCurrency(doc); team.values = getTopEleven(doc); const value = document.createElement("div"); value.style.color = "blue"; value.style.width = "100%"; value.style.marginTop = "3px"; value.innerText = `Top Eleven: ${formatBigNumber(team.values, ",")} ${currency}`; team.node.querySelector("td").appendChild(value); team.done = true; }, }); } async function fetchTeamValue(teams, username) { const url = `https://www.managerzone.com/xml/manager_data.php?username=${username}`; GM_xmlhttpRequest({ method: "GET", url: url, context: { teams, username }, onload: function (resp) { const parser = new DOMParser(); const doc = parser.parseFromString(resp.responseText, "text/xml"); const teamId = doc.querySelector('Team[sport="soccer"]').getAttribute("teamId"); fetchTopEleven(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 sortByTopEleven() { console.log("sorting in progress"); const tbody = document.querySelector("#federation_clash_members_list tbody"); const teams = []; for (const child of tbody.children) { const username = getUsername(child); teams.push({ node: child, username, teamId: "", values: 0, done: false, }); fetchTeamValue(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); tbody.replaceChildren(...newOrder); console.log("done"); setTableHeader(tableHeader + " ▼"); } else { timeout -= step; setTableHeader(tableHeader + " " + ".".repeat(1 + (dots % 3))); dots++; if (timeout < 0) { clearInterval(interval); setTableHeader(tableHeader + " (failed)"); console.log("timeout"); } } }, step); } /* *********************** Inject ********************************** */ function isFederationFrontPage(uri) { return uri.endsWith("/?p=federations") || uri.search("/?p=federations&fid=") > -1; } function inject() { if (document.baseURI.search("/?p=federations&sub=clash") > -1) { createModal(); addSquadButtonsToClashPage(); } else if (isFederationFrontPage(document.baseURI)) { sortByTopEleven(); } else if (document.baseURI.search("/?p=players&sub=alt") > -1) { const content = createSquadSummary(document); const place = document.querySelector("table#playerAltViewTable"); if (place) { place.parentNode?.insertBefore(content, place); } } } if (document.readyState === "loading") { // Loading hasn't finished yet document.addEventListener("DOMContentLoaded", inject); } else { // `DOMContentLoaded` has already fired inject(); } })();