您需要先安装一个扩展,例如 篡改猴、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(); })();