您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows the latest tactics used by an opponent
- // ==UserScript==
- // @name ylOppTacticsPreview (Modified)
- // @namespace douglaskampl
- // @version 5.0.1
- // @description Shows the latest tactics used by an opponent
- // @author kostrzak16 (feat. Douglas and xente)
- // @match https://www.managerzone.com/?p=match&sub=scheduled
- // @icon https://www.google.com/s2/favicons?sz=64&domain=managerzone.com
- // @grant GM_addStyle
- // @grant GM_getResourceText
- // @grant GM_getValue
- // @grant GM_setValue
- // @require https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js
- // @resource oppTacticsPreviewStyles https://br18.org/mz/userscript/other/Slezsko.css
- // @run-at document-idle
- // @license MIT
- // ==/UserScript==
- (function () {
- 'use strict';
- class OpponentTacticsPreview {
- static CONSTANTS = {
- MATCH_TYPE_GROUPS: {
- 'All': [
- { id: 'no_restriction', label: 'Senior' },
- { id: 'u23', label: 'U23' },
- { id: 'u21', label: 'U21' },
- { id: 'u18', label: 'U18' }
- ],
- 'World League': [
- { id: 'world_series', label: 'Senior WL' },
- { id: 'u23_world_series', label: 'U23 WL' },
- { id: 'u21_world_series', label: 'U21 WL' },
- { id: 'u18_world_series', label: 'U18 WL' }
- ],
- 'Official League': [
- { id: 'series', label: 'Senior League' },
- { id: 'u23_series', label: 'U23 League' },
- { id: 'u21_series', label: 'U21 League' },
- { id: 'u18_series', label: 'U18 League' }
- ]
- },
- URLS: {
- MATCH_STATS: (matchId) => `https://www.managerzone.com/matchviewer/getMatchFiles.php?type=stats&mid=${matchId}&sport=soccer`,
- MATCH_LIST: 'https://www.managerzone.com/ajax.php?p=matches&sub=list&sport=soccer',
- PITCH_IMAGE: (matchId) => `https://www.managerzone.com/dynimg/pitch.php?match_id=${matchId}`,
- MATCH_RESULT: (matchId) => `https://www.managerzone.com/?p=match&sub=result&mid=${matchId}`,
- CLUBHOUSE: 'https://www.managerzone.com/?p=clubhouse'
- },
- STORAGE_KEYS: {
- MATCH_LIMIT: 'ylopp_match_limit',
- SAVED_TEAMS: 'ylopp_saved_teams',
- USER_TEAM_ID: 'ylopp_user_team_id'
- },
- DEFAULTS: {
- MATCH_LIMIT: 10,
- MAX_SAVED_TEAMS: 15,
- MAX_MATCH_LIMIT: 100
- },
- SELECTORS: {
- FIXTURES_LIST: '#fixtures-results-list-wrapper',
- STATS_XENTE: '#legendDiv',
- ELO_SCHEDULED: '#eloScheduledSelect',
- HOME_TEAM: '.home-team-column.flex-grow-1',
- SELECT_WRAPPER: 'dd.set-default-wrapper'
- },
- };
- constructor() {
- this.ourTeamName = null;
- this.userTeamId = null;
- this.currentOpponentTid = '';
- this.spinnerInstance = null;
- this.observer = new MutationObserver(() => {
- this.insertIconsAndListeners();
- });
- }
- getMatchLimit() {
- return GM_getValue(OpponentTacticsPreview.CONSTANTS.STORAGE_KEYS.MATCH_LIMIT, OpponentTacticsPreview.CONSTANTS.DEFAULTS.MATCH_LIMIT);
- }
- setMatchLimit(limit) {
- const numericLimit = parseInt(limit, 10);
- if (!isNaN(numericLimit) && numericLimit > 0 && numericLimit <= OpponentTacticsPreview.CONSTANTS.DEFAULTS.MAX_MATCH_LIMIT) {
- GM_setValue(OpponentTacticsPreview.CONSTANTS.STORAGE_KEYS.MATCH_LIMIT, numericLimit);
- }
- }
- getSavedTeams() {
- return GM_getValue(OpponentTacticsPreview.CONSTANTS.STORAGE_KEYS.SAVED_TEAMS, []);
- }
- saveTeam(teamId, teamName) {
- if (!teamId || !teamName || teamName.startsWith('Team ')) {
- return;
- }
- let teams = this.getSavedTeams();
- const existingIndex = teams.findIndex(team => team.id === teamId);
- if (existingIndex > -1) {
- teams.splice(existingIndex, 1);
- }
- teams.unshift({ id: teamId, name: teamName });
- const trimmedTeams = teams.slice(0, OpponentTacticsPreview.CONSTANTS.DEFAULTS.MAX_SAVED_TEAMS);
- GM_setValue(OpponentTacticsPreview.CONSTANTS.STORAGE_KEYS.SAVED_TEAMS, trimmedTeams);
- }
- startObserving() {
- const fixturesList = document.querySelector(OpponentTacticsPreview.CONSTANTS.SELECTORS.FIXTURES_LIST);
- if (fixturesList) {
- this.observer.observe(fixturesList, { childList: true, subtree: true });
- }
- }
- showLoadingSpinner() {
- if (this.spinnerInstance) {
- return;
- }
- const spinnerContainer = document.createElement('div');
- spinnerContainer.id = 'spinjs-overlay';
- document.body.appendChild(spinnerContainer);
- this.spinnerInstance = new Spinner({ color: '#FFFFFF', lines: 12, top: '50%', left: '50%' }).spin(spinnerContainer);
- }
- hideLoadingSpinner() {
- if (this.spinnerInstance) {
- this.spinnerInstance.stop();
- this.spinnerInstance = null;
- }
- const spinnerContainer = document.getElementById('spinjs-overlay');
- if (spinnerContainer) {
- spinnerContainer.remove();
- }
- }
- extractTeamNameFromHtml(htmlDocument, teamId) {
- const nameCounts = new Map();
- const teamLinks = htmlDocument.querySelectorAll('.teams-wrapper a.clippable');
- teamLinks.forEach(link => {
- const linkUrl = new URL(link.href, location.href);
- const linkTid = linkUrl.searchParams.get('tid');
- if (linkTid === teamId) {
- const fullName = link.querySelector('.full-name')?.textContent.trim();
- if (fullName) {
- nameCounts.set(fullName, (nameCounts.get(fullName) || 0) + 1);
- }
- }
- });
- if (nameCounts.size > 0) {
- let mostCommonName = '';
- let maxCount = 0;
- for (const [name, count] of nameCounts.entries()) {
- if (count > maxCount) {
- maxCount = count;
- mostCommonName = name;
- }
- }
- return mostCommonName;
- }
- const boldTeamNameElement = htmlDocument.querySelector('.teams-wrapper a.clippable > strong > .full-name');
- if (boldTeamNameElement) {
- return boldTeamNameElement.textContent.trim();
- }
- return null;
- }
- async fetchLatestTactics(teamId, matchType) {
- const modal = document.getElementById('interaction-modal');
- if (modal) {
- this.fadeOutAndRemove(modal);
- }
- this.showLoadingSpinner();
- try {
- const response = await fetch(
- OpponentTacticsPreview.CONSTANTS.URLS.MATCH_LIST, {
- method: 'POST',
- headers: { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' },
- body: `type=played&hidescore=false&tid1=${teamId}&offset=&selectType=${matchType}&limit=max`,
- credentials: 'include'
- }
- );
- if (!response.ok) {
- throw new Error(`Network response was not ok: ${response.statusText}`);
- }
- const data = await response.json();
- const parser = new DOMParser();
- const htmlDocument = parser.parseFromString(data.list, 'text/html');
- const actualTeamName = this.extractTeamNameFromHtml(htmlDocument, teamId);
- const finalTeamName = actualTeamName || `Team ${teamId}`;
- this.saveTeam(teamId, finalTeamName);
- this.currentOpponentTid = teamId;
- this.processTacticsData(htmlDocument, matchType, finalTeamName);
- } catch (error) {
- console.error('Failed to fetch latest tactics:', error);
- } finally {
- this.hideLoadingSpinner();
- }
- }
- isRelevantMatch(entry) {
- const wrapper = entry.querySelector('.responsive-hide.match-reference-text-wrapper');
- if (!wrapper) {
- return true;
- }
- const hasLink = wrapper.querySelector('a');
- return hasLink !== null;
- }
- processTacticsData(htmlDocument, matchType, opponentName) {
- const matchEntries = htmlDocument.querySelectorAll('dl > dd.odd');
- const container = this.createTacticsContainer(matchType, opponentName);
- document.body.appendChild(container);
- const listWrapper = container.querySelector('.tactics-list');
- let processedCount = 0;
- const matchLimit = this.getMatchLimit();
- for (const entry of matchEntries) {
- if (processedCount >= matchLimit) {
- break;
- }
- if (!this.isRelevantMatch(entry)) {
- continue;
- }
- const link = entry.querySelector('a.score-shown');
- if (!link) {
- continue;
- }
- const dl = link.closest('dl');
- const theScore = link.textContent.trim();
- const homeTeamName = dl.querySelector('.home-team-column .full-name')?.textContent.trim() || 'Home';
- const awayTeamName = dl.querySelector('.away-team-column .full-name')?.textContent.trim() || 'Away';
- const mid = new URLSearchParams(new URL(link.href, location.href).search).get('mid');
- if (!mid) {
- continue;
- }
- let [homeGoals, awayGoals] = [0, 0];
- if (theScore.includes('-')) {
- const parts = theScore.split('-').map(x => parseInt(x.trim(), 10));
- if (parts.length === 2 && !isNaN(parts[0]) && !isNaN(parts[1])) {
- [homeGoals, awayGoals] = parts;
- }
- }
- const opponentIsHome = (homeTeamName === opponentName);
- const tacticUrl = OpponentTacticsPreview.CONSTANTS.URLS.PITCH_IMAGE(mid);
- const resultUrl = OpponentTacticsPreview.CONSTANTS.URLS.MATCH_RESULT(mid);
- const canvas = this.createCanvasWithReplacedColors(tacticUrl, opponentIsHome);
- const item = document.createElement('div');
- item.className = 'tactic-item';
- const opponentGoals = opponentIsHome ? homeGoals : awayGoals;
- const otherGoals = opponentIsHome ? awayGoals : homeGoals;
- if (opponentGoals > otherGoals) {
- item.classList.add('tactic-win');
- } else if (opponentGoals < otherGoals) {
- item.classList.add('tactic-loss');
- } else {
- item.classList.add('tactic-draw');
- }
- const linkA = document.createElement('a');
- linkA.href = resultUrl;
- linkA.target = '_blank';
- linkA.className = 'tactic-link';
- linkA.appendChild(canvas);
- const scoreP = document.createElement('p');
- scoreP.textContent = `${homeTeamName} ${theScore} ${awayTeamName}`;
- linkA.appendChild(scoreP);
- item.appendChild(linkA);
- this.addPlaystyleHover(mid, canvas, this.currentOpponentTid);
- listWrapper.appendChild(item);
- processedCount++;
- }
- if (processedCount === 0) {
- const message = document.createElement('div');
- message.className = 'no-tactics-message';
- message.textContent = 'No recent valid tactics found for this team and category.';
- listWrapper.appendChild(message);
- }
- container.classList.add('fade-in');
- }
- showInteractionModal(teamId, sourceElement) {
- const existingModal = document.getElementById('interaction-modal');
- if (existingModal) {
- this.fadeOutAndRemove(existingModal);
- }
- const modal = document.createElement('div');
- modal.id = 'interaction-modal';
- modal.classList.add('fade-in');
- const header = document.createElement('div');
- header.className = 'interaction-modal-header';
- const title = document.createElement('span');
- title.textContent = '';
- header.appendChild(title);
- const settingsIcon = document.createElement('span');
- settingsIcon.className = 'settings-icon';
- settingsIcon.innerHTML = '⚙';
- header.appendChild(settingsIcon);
- modal.appendChild(header);
- const teamInputSection = this.createTeamInputSection(modal, teamId);
- this.createTabbedButtons(modal, teamInputSection.teamIdInput);
- const settingsPanel = this.createSettingsPanel(modal);
- settingsIcon.onclick = () => {
- settingsPanel.style.display = settingsPanel.style.display === 'block' ? 'none' : 'block';
- };
- document.body.appendChild(modal);
- const rect = sourceElement.getBoundingClientRect();
- modal.style.position = 'absolute';
- modal.style.top = `${window.scrollY + rect.bottom + 5}px`;
- modal.style.left = `${window.scrollX + rect.left}px`;
- }
- createTeamInputSection(container, initialTeamId) {
- const section = document.createElement('div');
- section.className = 'interaction-section team-input-section';
- const label = document.createElement('label');
- label.textContent = 'Team ID:';
- label.htmlFor = 'team-id-input';
- section.appendChild(label);
- const teamIdInput = document.createElement('input');
- teamIdInput.type = 'text';
- teamIdInput.id = 'team-id-input';
- teamIdInput.value = initialTeamId;
- section.appendChild(teamIdInput);
- const select = this.createRecentsDropdown(teamIdInput);
- section.appendChild(select);
- container.appendChild(section);
- return { teamIdInput, recentsSelect: select };
- }
- createRecentsDropdown(teamIdInput) {
- const select = document.createElement('select');
- select.className = 'recents-select';
- const defaultOption = document.createElement('option');
- defaultOption.textContent = 'Recent Teams';
- defaultOption.value = '';
- select.appendChild(defaultOption);
- this.getSavedTeams().forEach(team => {
- const option = document.createElement('option');
- option.value = team.id;
- option.textContent = `${team.name} (${team.id})`;
- select.appendChild(option);
- });
- select.onchange = () => {
- if (select.value) {
- teamIdInput.value = select.value;
- }
- };
- return select;
- }
- createTabbedButtons(container, teamIdInput) {
- const tabContainer = document.createElement('div');
- tabContainer.className = 'tab-container';
- const tabHeaders = document.createElement('div');
- tabHeaders.className = 'tab-headers';
- const tabContents = document.createElement('div');
- tabContents.className = 'tab-contents';
- Object.entries(OpponentTacticsPreview.CONSTANTS.MATCH_TYPE_GROUPS).forEach(([groupName, types], index) => {
- const header = document.createElement('button');
- header.className = 'tab-header';
- header.textContent = groupName;
- const content = document.createElement('div');
- content.className = 'tab-content';
- types.forEach(type => {
- const button = document.createElement('button');
- button.textContent = type.label;
- button.onclick = () => {
- const teamId = teamIdInput.value.trim();
- if (teamId) {
- this.fetchLatestTactics(teamId, type.id);
- }
- };
- content.appendChild(button);
- });
- header.onclick = () => {
- tabContainer.querySelectorAll('.tab-header').forEach(h => h.classList.remove('active'));
- tabContainer.querySelectorAll('.tab-content').forEach(c => c.style.display = 'none');
- header.classList.add('active');
- content.style.display = 'flex';
- };
- tabHeaders.appendChild(header);
- tabContents.appendChild(content);
- if (index === 0) {
- header.classList.add('active');
- content.style.display = 'flex';
- } else {
- content.style.display = 'none';
- }
- });
- tabContainer.appendChild(tabHeaders);
- tabContainer.appendChild(tabContents);
- container.appendChild(tabContainer);
- }
- createSettingsPanel(modalContainer) {
- const panel = document.createElement('div');
- panel.className = 'settings-panel';
- panel.style.display = 'none';
- const limitLabel = document.createElement('label');
- limitLabel.textContent = `Match Limit (1-${OpponentTacticsPreview.CONSTANTS.DEFAULTS.MAX_MATCH_LIMIT}):`;
- panel.appendChild(limitLabel);
- const limitInput = document.createElement('input');
- limitInput.type = 'text';
- limitInput.inputMode = 'numeric';
- limitInput.pattern = '[0-9]*';
- limitInput.value = this.getMatchLimit();
- limitInput.oninput = () => {
- limitInput.value = limitInput.value.replace(/\D/g, '');
- };
- limitInput.onchange = () => this.setMatchLimit(limitInput.value);
- panel.appendChild(limitInput);
- modalContainer.appendChild(panel);
- return panel;
- }
- createTacticsContainer(matchType, opponent) {
- const existingContainer = document.getElementById('tactics-container');
- if (existingContainer) {
- this.fadeOutAndRemove(existingContainer);
- }
- const container = document.createElement('div');
- container.id = 'tactics-container';
- container.className = 'tactics-container';
- const header = document.createElement('div');
- header.className = 'tactics-header';
- const title = document.createElement('div');
- title.className = 'match-info-text';
- let matchTypeLabel = matchType;
- for (const group in OpponentTacticsPreview.CONSTANTS.MATCH_TYPE_GROUPS) {
- const found = OpponentTacticsPreview.CONSTANTS.MATCH_TYPE_GROUPS[group].find(t => t.id === matchType);
- if (found) {
- matchTypeLabel = found.label;
- break;
- }
- }
- title.innerHTML = `<div class="title-main">${opponent} (${matchTypeLabel})</div>`;
- header.appendChild(title);
- const closeButton = document.createElement('button');
- closeButton.className = 'close-button';
- closeButton.textContent = '×';
- closeButton.onclick = () => this.fadeOutAndRemove(container);
- header.appendChild(closeButton);
- container.appendChild(header);
- const listWrapper = document.createElement('div');
- listWrapper.className = 'tactics-list';
- container.appendChild(listWrapper);
- return container;
- }
- fadeOutAndRemove(el) {
- if (!el) {
- return;
- }
- el.classList.remove('fade-in');
- el.classList.add('fade-out');
- setTimeout(() => el.remove(), 200);
- }
- identifyUserTeamName() {
- const ddRows = document.querySelectorAll('#fixtures-results-list > dd.odd');
- if (ddRows.length === 0) {
- return null;
- }
- const countMap = new Map();
- ddRows.forEach(dd => {
- const homeName = dd.querySelector('.home-team-column .full-name')?.textContent.trim();
- const awayName = dd.querySelector('.away-team-column .full-name')?.textContent.trim();
- if (homeName) {
- countMap.set(homeName, (countMap.get(homeName) || 0) + 1);
- }
- if (awayName) {
- countMap.set(awayName, (countMap.get(awayName) || 0) + 1);
- }
- });
- for (const [name, count] of countMap.entries()) {
- if (count === ddRows.length) {
- return name;
- }
- }
- return null;
- }
- insertIconsAndListeners() {
- if (!this.ourTeamName) {
- this.ourTeamName = this.identifyUserTeamName();
- }
- if (!this.ourTeamName) {
- return;
- }
- document.querySelectorAll('dd.odd').forEach(dd => {
- const selectWrapper = dd.querySelector(OpponentTacticsPreview.CONSTANTS.SELECTORS.SELECT_WRAPPER);
- if (selectWrapper && !selectWrapper.querySelector('.magnifier-icon')) {
- const homeTeamName = dd.querySelector('.home-team-column .full-name')?.textContent.trim();
- const awayTeamName = dd.querySelector('.away-team-column .full-name')?.textContent.trim();
- const homeTeamLink = dd.querySelector('.home-team-column a.clippable');
- const awayTeamLink = dd.querySelector('.away-team-column a.clippable');
- let opponentName = null,
- opponentTid = null;
- if (homeTeamName === this.ourTeamName && awayTeamName && awayTeamLink) {
- opponentName = awayTeamName;
- const awayHref = awayTeamLink.href;
- if (awayHref) {
- opponentTid = new URLSearchParams(new URL(awayHref, location.href).search).get('tid');
- }
- } else if (awayTeamName === this.ourTeamName && homeTeamName && homeTeamLink) {
- opponentName = homeTeamName;
- const homeHref = homeTeamLink.href;
- if (homeHref) {
- opponentTid = new URLSearchParams(new URL(homeHref, location.href).search).get('tid');
- }
- }
- if (opponentName && opponentTid) {
- const iconWrapper = document.createElement('span');
- iconWrapper.className = 'magnifier-icon';
- iconWrapper.dataset.tid = opponentTid;
- iconWrapper.dataset.opponent = opponentName;
- iconWrapper.title = 'Check opponent latest tactics';
- iconWrapper.textContent = '🔍';
- const select = selectWrapper.querySelector('select');
- if (select) {
- select.insertAdjacentElement('afterend', iconWrapper);
- }
- }
- }
- });
- }
- createCanvasWithReplacedColors(imageUrl, opponentIsHome) {
- const canvas = document.createElement('canvas');
- canvas.width = 150;
- canvas.height = 200;
- const context = canvas.getContext('2d');
- const image = new Image();
- image.crossOrigin = 'Anonymous';
- image.onload = () => {
- if (opponentIsHome) {
- context.translate(canvas.width / 2, canvas.height / 2);
- context.rotate(Math.PI);
- context.translate(-canvas.width / 2, -canvas.height / 2);
- }
- context.drawImage(image, 0, 0, canvas.width, canvas.height);
- const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
- const data = imageData.data;
- const darkGreen = { r: 0, g: 100, b: 0 };
- for (let i = 0; i < data.length; i += 4) {
- const r = data[i],
- g = data[i + 1],
- b = data[i + 2];
- const isBlack = r < 30 && g < 30 && b < 30;
- const isYellow = r > 200 && g > 200 && b < 100;
- if (opponentIsHome) {
- if (isYellow) {
- data[i] = 0;
- data[i + 1] = 0;
- data[i + 2] = 0;
- } else if (isBlack) {
- data[i] = darkGreen.r;
- data[i + 1] = darkGreen.g;
- data[i + 2] = darkGreen.b;
- }
- } else {
- if (isBlack) {
- data[i] = 0;
- data[i + 1] = 0;
- data[i + 2] = 0;
- } else if (isYellow) {
- data[i] = darkGreen.r;
- data[i + 1] = darkGreen.g;
- data[i + 2] = darkGreen.b;
- }
- }
- }
- const tempData = new Uint8ClampedArray(data);
- for (let y = 1; y < canvas.height - 1; y++) {
- for (let x = 1; x < canvas.width - 1; x++) {
- const i = (y * canvas.width + x) * 4;
- if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0) {
- for (let dy = -1; dy <= 1; dy++) {
- for (let dx = -1; dx <= 1; dx++) {
- if (dx === 0 && dy === 0) {
- continue;
- }
- const ni = ((y + dy) * canvas.width + (x + dx)) * 4;
- if (!(data[ni] === 0 && data[ni + 1] === 0 && data[ni + 2] === 0)) {
- tempData[i] = 255;
- tempData[i + 1] = 255;
- tempData[i + 2] = 255;
- }
- }
- }
- }
- }
- }
- context.putImageData(new ImageData(tempData, canvas.width, canvas.height), 0, 0);
- };
- image.src = imageUrl;
- return canvas;
- }
- async fetchPlaystyleChanges(mid, opponentTid) {
- try {
- const res = await fetch(OpponentTacticsPreview.CONSTANTS.URLS.MATCH_STATS(mid));
- const txt = await res.text();
- const xml = new DOMParser().parseFromString(txt, 'text/xml');
- const changes = Array.from(xml.querySelectorAll('Events Tactic'))
- .filter(n => n.getAttribute('teamId') === opponentTid)
- .map(n => {
- const tType = n.getAttribute('type');
- if (['playstyle', 'aggression', 'tactic'].includes(tType)) {
- return `Min ${n.getAttribute('time')}: ${tType} → ${n.getAttribute('new_setting')}`;
- }
- return null;
- }).filter(Boolean);
- return changes.length ? changes.join('<br>') : 'No relevant changes detected';
- } catch (e) {
- return 'Could not fetch playstyle data.';
- }
- }
- addPlaystyleHover(mid, canvas, opponentTid) {
- const tooltip = document.createElement('div');
- tooltip.className = 'playstyle-tooltip';
- document.body.appendChild(tooltip);
- canvas.addEventListener('mouseover', async (ev) => {
- tooltip.style.display = 'block';
- tooltip.innerHTML = 'Loading...';
- const info = await this.fetchPlaystyleChanges(mid, opponentTid);
- tooltip.innerHTML = info;
- tooltip.style.top = `${ev.pageY + 15}px`;
- tooltip.style.left = `${ev.pageX + 5}px`;
- });
- canvas.addEventListener('mousemove', (ev) => {
- tooltip.style.top = `${ev.pageY + 15}px`;
- tooltip.style.left = `${ev.pageX + 5}px`;
- });
- canvas.addEventListener('mouseout', () => {
- tooltip.style.display = 'none';
- });
- }
- waitForEloValues() {
- const interval = setInterval(() => {
- const elements = document.querySelectorAll(OpponentTacticsPreview.CONSTANTS.SELECTORS.HOME_TEAM);
- if (elements.length > 0 && elements[elements.length - 1]?.innerHTML.includes('br')) {
- clearInterval(interval);
- this.insertIconsAndListeners();
- }
- }, 100);
- setTimeout(() => clearInterval(interval), 1500);
- }
- handleClickEvents(e) {
- const clickedMagnifier = e.target.closest('.magnifier-icon');
- if (clickedMagnifier) {
- e.preventDefault();
- e.stopPropagation();
- const tid = clickedMagnifier.dataset.tid;
- const name = clickedMagnifier.dataset.opponent;
- if (!tid) {
- return;
- }
- this.saveTeam(tid, name);
- this.showInteractionModal(tid, clickedMagnifier);
- return;
- }
- const interactionModal = document.getElementById('interaction-modal');
- const tacticsContainer = document.getElementById('tactics-container');
- if (interactionModal && !interactionModal.contains(e.target)) {
- this.fadeOutAndRemove(interactionModal);
- }
- if (tacticsContainer && !tacticsContainer.contains(e.target)) {
- this.fadeOutAndRemove(tacticsContainer);
- }
- }
- async initializeUserTeamId() {
- let storedId = GM_getValue(OpponentTacticsPreview.CONSTANTS.STORAGE_KEYS.USER_TEAM_ID, null);
- if (storedId) {
- this.userTeamId = storedId;
- return;
- }
- try {
- const response = await fetch(OpponentTacticsPreview.CONSTANTS.URLS.CLUBHOUSE);
- const text = await response.text();
- const match = text.match(/dynimg\/badge\.php\?team_id=(\d+)/);
- if (match && match[1]) {
- this.userTeamId = match[1];
- GM_setValue(OpponentTacticsPreview.CONSTANTS.STORAGE_KEYS.USER_TEAM_ID, this.userTeamId);
- }
- } catch (error) {
- console.error('Could not fetch user team ID.', error);
- }
- }
- async init() {
- GM_addStyle(GM_getResourceText('oppTacticsPreviewStyles'));
- await this.initializeUserTeamId();
- const statsXenteRunning = document.querySelector(OpponentTacticsPreview.CONSTANTS.SELECTORS.STATS_XENTE);
- const eloScheduledSelected = document.querySelector(OpponentTacticsPreview.CONSTANTS.SELECTORS.ELO_SCHEDULED)?.checked;
- if (statsXenteRunning && eloScheduledSelected) {
- this.waitForEloValues();
- } else {
- this.insertIconsAndListeners();
- }
- this.startObserving();
- document.body.addEventListener('click', this.handleClickEvents.bind(this), true);
- }
- }
- const プレビュー = new OpponentTacticsPreview();
- プレビュー.init();
- })();