MZ Tactics Selector

Adds a dropdown menu with overused tactics.

目前为 2023-06-09 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name MZ Tactics Selector
  3. // @namespace essenfc
  4. // @version 4.3
  5. // @description Adds a dropdown menu with overused tactics.
  6. // @author Douglas Vieira
  7. // @match https://www.managerzone.com/?p=tactics
  8. // @match https://www.managerzone.com/?p=national_teams&sub=tactics&type=*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=managerzone.com
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. const fontLink = document.createElement("link");
  16. fontLink.href =
  17. "https://fonts.googleapis.com/css2?family=Montserrat&display=swap";
  18. fontLink.rel = "stylesheet";
  19. document.head.appendChild(fontLink);
  20.  
  21. let modal;
  22.  
  23. (function () {
  24. "use strict";
  25.  
  26. let dropdownTactics = [];
  27.  
  28. const defaultTacticsDataUrl =
  29. "https://raw.githubusercontent.com/douglasdotv/tactics-selector/main/tactics.json?callback=?";
  30.  
  31. const outfieldPlayersSelector =
  32. ".fieldpos.fieldpos-ok.ui-draggable:not(.substitute):not(.goalkeeper):not(.substitute.goalkeeper), .fieldpos.fieldpos-collision.ui-draggable:not(.substitute):not(.goalkeeper):not(.substitute.goalkeeper)";
  33.  
  34. window.addEventListener("load", function () {
  35. const tacticsSelectorDiv = createTacSelDiv();
  36. const dropdown = createDropdownMenu();
  37. const dropdownDescription = createDropdownDescription();
  38. const addNewTacticBtn = createAddNewTacticButton();
  39. const deleteTacticBtn = createDeleteTacticButton();
  40. const renameTacticBtn = createRenameTacticButton();
  41. const updateTacticBtn = createUpdateTacticButton();
  42. const clearTacticsBtn = createClearTacticsButton();
  43. const resetTacticsBtn = createResetTacticsButton();
  44. const importTacticsBtn = createImportTacticsButton();
  45. const exportTacticsBtn = createExportTacticsButton();
  46. const aboutBtn = createAboutButton();
  47. const hiBtn = createHiButton();
  48.  
  49. appendChildren(tacticsSelectorDiv, [
  50. dropdownDescription,
  51. dropdown,
  52. addNewTacticBtn,
  53. deleteTacticBtn,
  54. renameTacticBtn,
  55. updateTacticBtn,
  56. clearTacticsBtn,
  57. resetTacticsBtn,
  58. importTacticsBtn,
  59. exportTacticsBtn,
  60. aboutBtn,
  61. hiBtn,
  62. ]);
  63.  
  64. if (isSoccerTacticsPage()) {
  65. insertAfterElement(
  66. tacticsSelectorDiv,
  67. document.getElementById("tactics_box")
  68. );
  69. }
  70.  
  71. modal = createInfoModal();
  72. document.body.appendChild(modal);
  73. document.addEventListener("click", function (event) {
  74. if (modal.style.display === "block" && !modal.contains(event.target)) {
  75. modal.style.display = "none";
  76. }
  77. });
  78.  
  79. fetchTacticsFromLocalStorage()
  80. .then((data) => {
  81. dropdownTactics = data.tactics;
  82.  
  83. dropdownTactics.sort((a, b) => {
  84. return a.name.localeCompare(b.name);
  85. });
  86.  
  87. addTacticsToDropdown(dropdown, dropdownTactics);
  88.  
  89. dropdown.addEventListener("change", function () {
  90. handleTacticSelection(this.value);
  91. });
  92. })
  93. .catch((err) => {
  94. console.error("Couldn't fetch data from json: ", err);
  95. });
  96. });
  97.  
  98. function createTacSelDiv() {
  99. const myDiv = document.createElement("div");
  100. myDiv.id = "tactics_selector_div";
  101. myDiv.style.width = "100%";
  102. myDiv.style.display = "flex";
  103. myDiv.style.flexWrap = "wrap";
  104. myDiv.style.alignItems = "center";
  105. myDiv.style.justifyContent = "flex-start";
  106. myDiv.style.marginTop = "6px";
  107. myDiv.style.marginLeft = "6px";
  108. return myDiv;
  109. }
  110.  
  111. // _____Dropdown Menu_____
  112.  
  113. function createDropdownMenu() {
  114. const dropdown = document.createElement("select");
  115. setupDropdownMenu(dropdown);
  116.  
  117. const placeholderOption = createPlaceholderOption();
  118. appendChildren(dropdown, [placeholderOption]);
  119.  
  120. return dropdown;
  121. }
  122.  
  123. function setupDropdownMenu(dropdown) {
  124. dropdown.id = "tacticsDropdown";
  125. dropdown.style.fontSize = "12px";
  126. dropdown.style.fontFamily = "Montserrat, sans-serif";
  127. dropdown.style.border = "2px solid #000";
  128. dropdown.style.borderRadius = "2px";
  129. dropdown.style.background = "linear-gradient(to right, #add8e6, #e6f7ff)";
  130. dropdown.style.color = "#000";
  131. dropdown.style.boxShadow = "3px 3px 5px rgba(0, 0, 0, 0.2)";
  132. dropdown.style.cursor = "pointer";
  133. dropdown.style.outline = "none";
  134. dropdown.style.margin = "6px";
  135. }
  136.  
  137. function createPlaceholderOption() {
  138. const placeholderOption = document.createElement("option");
  139. placeholderOption.value = "";
  140. placeholderOption.text = "";
  141. placeholderOption.disabled = true;
  142. placeholderOption.selected = true;
  143. return placeholderOption;
  144. }
  145.  
  146. function createDropdownDescription() {
  147. const description = document.createElement("span");
  148. description.textContent = "Select a tactic: ";
  149. description.style.fontFamily = "Montserrat, sans-serif";
  150. description.style.fontSize = "12px";
  151. description.style.color = "#000";
  152. return description;
  153. }
  154.  
  155. function createHiButton() {
  156. const button = document.createElement("button");
  157. button.id = "hiButton";
  158. button.textContent = "";
  159. button.style.visibility = "hidden";
  160.  
  161. button.addEventListener("click", function () {
  162. const presetDropdown = document.getElementById("tactics_preset");
  163. presetDropdown.value = "5-3-2";
  164. presetDropdown.dispatchEvent(new Event("change"));
  165. });
  166.  
  167. return button;
  168. }
  169.  
  170. async function fetchTacticsFromLocalStorage() {
  171. const storedTactics = GM_getValue("ls_tactics");
  172. if (storedTactics) {
  173. return storedTactics;
  174. } else {
  175. const jsonTactics = await fetchTacticsFromJson();
  176. storeTacticsInLocalStorage(jsonTactics);
  177. return jsonTactics;
  178. }
  179. }
  180.  
  181. async function fetchTacticsFromJson() {
  182. const response = await fetch(defaultTacticsDataUrl);
  183. return await response.json();
  184. }
  185.  
  186. function storeTacticsInLocalStorage(data) {
  187. GM_setValue("ls_tactics", data);
  188. }
  189.  
  190. function addTacticsToDropdown(dropdown, tactics) {
  191. for (const tactic of tactics) {
  192. const option = document.createElement("option");
  193. option.value = tactic.name;
  194. option.text = tactic.name;
  195. dropdown.appendChild(option);
  196. }
  197. }
  198.  
  199. function handleTacticSelection(tactic) {
  200. let outfieldPlayers = Array.from(
  201. document.querySelectorAll(outfieldPlayersSelector)
  202. );
  203.  
  204. const selectedTactic = dropdownTactics.find(
  205. (tacticData) => tacticData.name === tactic
  206. );
  207.  
  208. if (selectedTactic) {
  209. if (outfieldPlayers.length < 10) {
  210. const hiButton = document.getElementById("hiButton");
  211. hiButton.click();
  212. setTimeout(() => rearrangePlayers(selectedTactic.coordinates), 1);
  213. } else {
  214. rearrangePlayers(selectedTactic.coordinates);
  215. }
  216. }
  217. }
  218.  
  219. function rearrangePlayers(coordinates) {
  220. const outfieldPlayers = Array.from(
  221. document.querySelectorAll(outfieldPlayersSelector)
  222. );
  223.  
  224. findBestPositions(outfieldPlayers, coordinates);
  225.  
  226. for (let i = 0; i < outfieldPlayers.length; ++i) {
  227. outfieldPlayers[i].style.left = coordinates[i][0] + "px";
  228. outfieldPlayers[i].style.top = coordinates[i][1] + "px";
  229. checkForCollision(outfieldPlayers[i]);
  230. }
  231. }
  232.  
  233. function findBestPositions(players, coordinates) {
  234. players.sort((a, b) => parseInt(a.style.top) - parseInt(b.style.top));
  235. coordinates.sort((a, b) => a[1] - b[1]);
  236. }
  237.  
  238. function checkForCollision(player) {
  239. if (player.classList.contains("fieldpos-collision")) {
  240. player.classList.remove("fieldpos-collision");
  241. player.classList.add("fieldpos-ok");
  242. }
  243. }
  244.  
  245. // _____Add new tactic_____
  246.  
  247. function createAddNewTacticButton() {
  248. const button = document.createElement("button");
  249. button.id = "addNewTacticButton";
  250. button.textContent = "Add current tactic";
  251. button.style.fontFamily = "Montserrat, sans-serif";
  252. button.style.fontSize = "12px";
  253. button.style.color = "#000";
  254. button.style.marginLeft = "6px";
  255. button.style.cursor = "pointer";
  256.  
  257. button.addEventListener("click", function () {
  258. addNewTactic().catch(console.error);
  259. });
  260.  
  261. return button;
  262. }
  263.  
  264. async function addNewTactic() {
  265. let dropdown = document.getElementById("tacticsDropdown");
  266.  
  267. let outfieldPlayers = Array.from(
  268. document.querySelectorAll(outfieldPlayersSelector)
  269. );
  270. if (!validateTacticPlayerCount(outfieldPlayers)) {
  271. return;
  272. }
  273.  
  274. const tacticName = prompt("Please enter a name for the tactic: ");
  275. const isValidName = await validateTacticName(tacticName);
  276. if (!isValidName) {
  277. return;
  278. }
  279.  
  280. let coordinates = outfieldPlayers.map((player) => [
  281. parseInt(player.style.left),
  282. parseInt(player.style.top),
  283. ]);
  284.  
  285. let tactic = {
  286. name: tacticName,
  287. coordinates,
  288. id: generateUniqueId(),
  289. };
  290.  
  291. saveTacticToStorage(tactic).catch(console.error);
  292. addTacticsToDropdown(dropdown, [tactic]);
  293. dropdownTactics.push(tactic);
  294.  
  295. dropdown.value = tactic.name;
  296. handleTacticSelection(tactic.name);
  297.  
  298. alert("A new tactic has been added.");
  299. }
  300.  
  301. function validateTacticPlayerCount(outfieldPlayers) {
  302. let isGoalkeeper = document.querySelector(
  303. ".fieldpos.fieldpos-ok.goalkeeper.ui-draggable"
  304. );
  305.  
  306. outfieldPlayers = outfieldPlayers.filter(
  307. (player) => !player.classList.contains("fieldpos-collision")
  308. );
  309.  
  310. if (outfieldPlayers.length < 10 || !isGoalkeeper) {
  311. alert(
  312. "Error: invalid tactic. You must have 1 goalkeeper and 10 outfield players in valid positions."
  313. );
  314. return false;
  315. }
  316.  
  317. return true;
  318. }
  319.  
  320. async function validateTacticName(name) {
  321. if (!name) {
  322. alert("Error: you must provide a name for the tactic.");
  323. return false;
  324. }
  325.  
  326. const tacticsData = (await GM_getValue("ls_tactics")) || { tactics: [] };
  327. if (tacticsData.tactics.some((t) => t.name === name)) {
  328. alert(
  329. "Error: a tactic with this name already exists. Please choose a different name."
  330. );
  331. return false;
  332. }
  333.  
  334. if (name.length > 50) {
  335. alert("Error: tactic name must be less than 50 characters.");
  336. return false;
  337. }
  338.  
  339. return true;
  340. }
  341.  
  342. async function saveTacticToStorage(tactic) {
  343. const tacticsData = (await GM_getValue("ls_tactics")) || { tactics: [] };
  344. tacticsData.tactics.push(tactic);
  345. await GM_setValue("ls_tactics", tacticsData);
  346. }
  347.  
  348. // _____Delete tactic_____
  349.  
  350. function createDeleteTacticButton() {
  351. const button = document.createElement("button");
  352. button.id = "deleteTacticButton";
  353. button.textContent = "Delete tactic";
  354. button.style.fontFamily = "Montserrat, sans-serif";
  355. button.style.fontSize = "12px";
  356. button.style.color = "#000";
  357. button.style.marginLeft = "6px";
  358. button.style.cursor = "pointer";
  359.  
  360. button.addEventListener("click", function () {
  361. deleteTactic().catch(console.error);
  362. });
  363.  
  364. return button;
  365. }
  366.  
  367. async function deleteTactic() {
  368. let dropdown = document.getElementById("tacticsDropdown");
  369. let selectedTactic = dropdownTactics.find(
  370. (tactic) => tactic.name === dropdown.value
  371. );
  372.  
  373. if (!selectedTactic) {
  374. alert("Error: no tactic selected.");
  375. return;
  376. }
  377.  
  378. const confirmed = confirm(
  379. `Are you sure you want to delete the tactic "${selectedTactic.name}"?`
  380. );
  381.  
  382. if (!confirmed) {
  383. return;
  384. }
  385.  
  386. alert(`Tactic "${selectedTactic.name}" was successfully deleted!`);
  387.  
  388. const tacticsData = (await GM_getValue("ls_tactics")) || { tactics: [] };
  389. tacticsData.tactics = tacticsData.tactics.filter(
  390. (tactic) => tactic.id !== selectedTactic.id
  391. );
  392.  
  393. await GM_setValue("ls_tactics", tacticsData);
  394.  
  395. dropdownTactics = dropdownTactics.filter(
  396. (tactic) => tactic.id !== selectedTactic.id
  397. );
  398.  
  399. const selectedOption = Array.from(dropdown.options).find(
  400. (option) => option.value === selectedTactic.name
  401. );
  402. dropdown.remove(selectedOption.index);
  403.  
  404. if (dropdown.options[0]?.disabled) {
  405. dropdown.selectedIndex = 0;
  406. }
  407. }
  408.  
  409. // _____Rename tactic_____
  410.  
  411. function createRenameTacticButton() {
  412. const button = document.createElement("button");
  413. button.id = "renameTacticButton";
  414. button.textContent = "Rename tactic";
  415. button.style.fontFamily = "Montserrat, sans-serif";
  416. button.style.fontSize = "12px";
  417. button.style.color = "#000";
  418. button.style.marginLeft = "6px";
  419. button.style.cursor = "pointer";
  420.  
  421. button.addEventListener("click", function () {
  422. renameTactic().catch(console.error);
  423. });
  424.  
  425. return button;
  426. }
  427.  
  428. async function renameTactic() {
  429. let dropdown = document.getElementById("tacticsDropdown");
  430. let selectedTactic = dropdownTactics.find(
  431. (tactic) => tactic.name === dropdown.value
  432. );
  433.  
  434. if (!selectedTactic) {
  435. alert("Error: no tactic selected.");
  436. return;
  437. }
  438.  
  439. const newName = prompt("Please enter a new name for this tactic: ");
  440. const isValidName = await validateTacticName(newName);
  441. if (!isValidName) {
  442. return;
  443. }
  444.  
  445. const selectedOption = Array.from(dropdown.options).find(
  446. (option) => option.value === selectedTactic.name
  447. );
  448.  
  449. const tacticsData = (await GM_getValue("ls_tactics")) || { tactics: [] };
  450. tacticsData.tactics = tacticsData.tactics.map((tactic) => {
  451. if (tactic.id === selectedTactic.id) {
  452. tactic.name = newName;
  453. }
  454. return tactic;
  455. });
  456.  
  457. await GM_setValue("ls_tactics", tacticsData);
  458.  
  459. dropdownTactics = dropdownTactics.map((tactic) => {
  460. if (tactic.id === selectedTactic.id) {
  461. tactic.name = newName;
  462. }
  463. return tactic;
  464. });
  465.  
  466. selectedOption.value = newName;
  467. selectedOption.textContent = newName;
  468.  
  469. alert("Tactic was successfully renamed!");
  470. }
  471.  
  472. // _____Update tactic_____
  473.  
  474. function createUpdateTacticButton() {
  475. const button = document.createElement("button");
  476. button.id = "updateTacticButton";
  477. button.textContent = "Update tactic";
  478. button.style.fontFamily = "Montserrat, sans-serif";
  479. button.style.fontSize = "12px";
  480. button.style.color = "#000";
  481. button.style.marginLeft = "6px";
  482. button.style.cursor = "pointer";
  483.  
  484. button.addEventListener("click", function () {
  485. updateTactic().catch(console.error);
  486. });
  487.  
  488. return button;
  489. }
  490.  
  491. async function updateTactic() {
  492. let dropdown = document.getElementById("tacticsDropdown");
  493. let outfieldPlayers = Array.from(
  494. document.querySelectorAll(outfieldPlayersSelector)
  495. );
  496.  
  497. let selectedTactic = dropdownTactics.find(
  498. (tactic) => tactic.name === dropdown.value
  499. );
  500.  
  501. if (!selectedTactic) {
  502. alert("Error: no tactic selected.");
  503. return;
  504. }
  505.  
  506. const confirmed = confirm(
  507. `Are you sure you want to update "${selectedTactic.name}" coordinates?`
  508. );
  509.  
  510. if (!confirmed) {
  511. return;
  512. }
  513.  
  514. alert(
  515. `Tactic "${selectedTactic.name}" coordinates were successfully updated!`
  516. );
  517.  
  518. let updatedCoordinates = outfieldPlayers.map((player) => [
  519. parseInt(player.style.left),
  520. parseInt(player.style.top),
  521. ]);
  522.  
  523. const tacticsData = (await GM_getValue("ls_tactics")) || { tactics: [] };
  524.  
  525. for (let tactic of tacticsData.tactics) {
  526. if (tactic.id === selectedTactic.id) {
  527. tactic.coordinates = updatedCoordinates;
  528. }
  529. }
  530.  
  531. for (let tactic of dropdownTactics) {
  532. if (tactic.id === selectedTactic.id) {
  533. tactic.coordinates = updatedCoordinates;
  534. }
  535. }
  536.  
  537. await GM_setValue("ls_tactics", tacticsData);
  538. }
  539.  
  540. // _____Clear tactics_____
  541.  
  542. function createClearTacticsButton() {
  543. const button = document.createElement("button");
  544. button.id = "clearButton";
  545. button.textContent = "Clear tactics";
  546. button.style.fontFamily = "Montserrat, sans-serif";
  547. button.style.fontSize = "12px";
  548. button.style.color = "#000";
  549. button.style.marginLeft = "6px";
  550. button.style.cursor = "pointer";
  551.  
  552. button.addEventListener("click", function () {
  553. clearTactics().catch(console.error);
  554. });
  555.  
  556. return button;
  557. }
  558.  
  559. async function clearTactics() {
  560. const confirmed = confirm(
  561. "Are you sure you want to clear all tactics? This action will delete all saved tactics and cannot be undone."
  562. );
  563.  
  564. if (!confirmed) {
  565. return;
  566. }
  567.  
  568. await GM_setValue("ls_tactics", { tactics: [] });
  569. dropdownTactics = [];
  570.  
  571. const dropdown = document.getElementById("tacticsDropdown");
  572. dropdown.innerHTML = "";
  573. dropdown.disabled = true;
  574.  
  575. alert("Tactics successfully cleared!");
  576. }
  577.  
  578. // _____Reset default settings_____
  579.  
  580. function createResetTacticsButton() {
  581. const button = document.createElement("button");
  582. button.id = "resetButton";
  583. button.textContent = "Reset tactics";
  584. button.style.fontFamily = "Montserrat, sans-serif";
  585. button.style.fontSize = "12px";
  586. button.style.color = "#000";
  587. button.style.marginLeft = "6px";
  588. button.style.cursor = "pointer";
  589.  
  590. button.addEventListener("click", function () {
  591. resetTactics().catch(console.error);
  592. });
  593.  
  594. return button;
  595. }
  596.  
  597. async function resetTactics() {
  598. const confirmed = confirm(
  599. "Are you sure you want to reset? This action will overwrite all saved tactics and cannot be undone."
  600. );
  601.  
  602. if (!confirmed) {
  603. return;
  604. }
  605.  
  606. const response = await fetch(defaultTacticsDataUrl);
  607. const data = await response.json();
  608. const defaultTactics = data.tactics;
  609.  
  610. await GM_setValue("ls_tactics", { tactics: defaultTactics });
  611. dropdownTactics = defaultTactics;
  612.  
  613. const dropdown = document.getElementById("tacticsDropdown");
  614. dropdown.innerHTML = "";
  615. dropdown.appendChild(createPlaceholderOption());
  616. addTacticsToDropdown(dropdown, dropdownTactics);
  617. dropdown.disabled = false;
  618.  
  619. alert("Reset done!");
  620. }
  621.  
  622. // _____Import/Export_____
  623.  
  624. function createImportTacticsButton() {
  625. const button = document.createElement("button");
  626. button.id = "importButton";
  627. button.textContent = "Import tactics";
  628. button.style.fontFamily = "Montserrat, sans-serif";
  629. button.style.fontSize = "12px";
  630. button.style.color = "#000";
  631. button.style.marginLeft = "6px";
  632. button.style.cursor = "pointer";
  633.  
  634. button.addEventListener("click", function () {
  635. importTactics().catch(console.error);
  636. });
  637.  
  638. return button;
  639. }
  640.  
  641. function createExportTacticsButton() {
  642. const button = document.createElement("button");
  643. button.id = "exportButton";
  644. button.textContent = "Export tactics";
  645. button.style.fontFamily = "Montserrat, sans-serif";
  646. button.style.fontSize = "12px";
  647. button.style.color = "#000";
  648. button.style.marginLeft = "6px";
  649. button.style.cursor = "pointer";
  650. button.addEventListener("click", exportTactics);
  651. return button;
  652. }
  653.  
  654. async function importTactics() {
  655. const input = document.createElement("input");
  656. input.type = "file";
  657. input.accept = ".json";
  658.  
  659. input.onchange = async function (event) {
  660. const file = event.target.files[0];
  661. const reader = new FileReader();
  662.  
  663. reader.onload = async function (event) {
  664. const importedTactics = JSON.parse(event.target.result).tactics;
  665.  
  666. let existingTactics = await GM_getValue("ls_tactics", { tactics: [] });
  667. existingTactics = existingTactics.tactics;
  668.  
  669. const mergedTactics = [...existingTactics];
  670. for (const importedTactic of importedTactics) {
  671. if (
  672. !existingTactics.some((tactic) => tactic.id === importedTactic.id)
  673. ) {
  674. mergedTactics.push(importedTactic);
  675. }
  676. }
  677.  
  678. await GM_setValue("ls_tactics", { tactics: mergedTactics });
  679.  
  680. mergedTactics.sort((a, b) => a.name.localeCompare(b.name));
  681. dropdownTactics = mergedTactics;
  682.  
  683. const dropdown = document.getElementById("tacticsDropdown");
  684. dropdown.innerHTML = "";
  685. dropdown.append(createPlaceholderOption());
  686. addTacticsToDropdown(dropdown, dropdownTactics);
  687. dropdown.disabled = false;
  688. };
  689.  
  690. reader.readAsText(file);
  691. };
  692.  
  693. input.click();
  694. }
  695.  
  696. function exportTactics() {
  697. const tactics = GM_getValue("ls_tactics", { tactics: [] });
  698. const tacticsJson = JSON.stringify(tactics);
  699. const blob = new Blob([tacticsJson], { type: "application/json" });
  700. const url = URL.createObjectURL(blob);
  701.  
  702. const link = document.createElement("a");
  703. link.href = url;
  704. link.download = "tactics.json";
  705. link.click();
  706.  
  707. URL.revokeObjectURL(url);
  708. }
  709.  
  710. // _____About button_____
  711.  
  712. function createAboutButton() {
  713. const button = document.createElement("button");
  714. button.id = "aboutButton";
  715. button.textContent = "About";
  716. button.style.fontFamily = "Montserrat, sans-serif";
  717. button.style.fontSize = "12px";
  718. button.style.color = "#000";
  719. button.style.marginLeft = "6px";
  720. button.style.cursor = "pointer";
  721.  
  722. button.addEventListener("click", function (event) {
  723. event.stopPropagation();
  724. if (modal.style.display === "none" || modal.style.opacity === "0") {
  725. showInfo();
  726. }
  727. });
  728.  
  729. return button;
  730. }
  731.  
  732. function showInfo() {
  733. modal.style.display = "block";
  734. setTimeout(function () {
  735. modal.style.opacity = "1";
  736. }, 0);
  737. }
  738.  
  739. function hideInfo() {
  740. modal.style.opacity = "0";
  741. setTimeout(function () {
  742. modal.style.display = "none";
  743. }, 500);
  744. }
  745.  
  746. function createInfoModal() {
  747. const modal = document.createElement("div");
  748. setupInfoModal(modal);
  749.  
  750. const modalContent = createModalContent();
  751. modal.appendChild(modalContent);
  752.  
  753. window.onclick = function (event) {
  754. if (event.target == modal) {
  755. hideInfo();
  756. }
  757. };
  758.  
  759. return modal;
  760. }
  761.  
  762. function setupInfoModal(modal) {
  763. modal.id = "infoModal";
  764. modal.style.display = "none";
  765. modal.style.position = "fixed";
  766. modal.style.zIndex = "1";
  767. modal.style.left = "50%";
  768. modal.style.top = "50%";
  769. modal.style.transform = "translate(-50%, -50%)";
  770. modal.style.opacity = "0";
  771. modal.style.transition = "opacity 0.5s ease-in-out";
  772. }
  773.  
  774. function createModalContent() {
  775. const modalContent = document.createElement("div");
  776. styleModalContent(modalContent);
  777.  
  778. const title = createTitle();
  779. const infoText = createInfoText();
  780. const feedbackText = createFeedbackText();
  781.  
  782. modalContent.appendChild(title);
  783. modalContent.appendChild(infoText);
  784. modalContent.appendChild(feedbackText);
  785.  
  786. return modalContent;
  787. }
  788.  
  789. function styleModalContent(content) {
  790. content.style.backgroundColor = "#fefefe";
  791. content.style.margin = "auto";
  792. content.style.padding = "20px";
  793. content.style.border = "1px solid #888";
  794. content.style.width = "80%";
  795. content.style.maxWidth = "500px";
  796. content.style.borderRadius = "10px";
  797. content.style.fontFamily = "Montserrat, sans-serif";
  798. content.style.textAlign = "center";
  799. content.style.color = "#000";
  800. content.style.fontSize = "16px";
  801. content.style.lineHeight = "1.5";
  802. }
  803.  
  804. function createTitle() {
  805. const title = document.createElement("h2");
  806. title.textContent = "MZ Tactics Selector";
  807. title.style.fontSize = "24px";
  808. title.style.fontWeight = "bold";
  809. title.style.marginBottom = "20px";
  810. return title;
  811. }
  812.  
  813. function createInfoText() {
  814. const infoText = document.createElement("p");
  815. infoText.innerHTML =
  816. 'For instructions, click <a href="https://greasyfork.org/pt-BR/scripts/467712-mz-tactics-selector" style="color: #007BFF;">here</a>.';
  817. return infoText;
  818. }
  819.  
  820. function createFeedbackText() {
  821. const feedbackText = document.createElement("p");
  822. feedbackText.innerHTML =
  823. 'If you run into any issues or have any suggestions, contact me here: <a href="https://www.managerzone.com/?p=guestbook&uid=8623925"><img src="https://www.managerzone.com/img/soccer/reply_guestbook.gif"></a>';
  824. return feedbackText;
  825. }
  826.  
  827. // _____Other_____
  828.  
  829. function appendChildren(element, children) {
  830. children.forEach((ch) => {
  831. element.appendChild(ch);
  832. });
  833. }
  834.  
  835. function insertAfterElement(toBeInserted, element) {
  836. element.parentNode.insertBefore(toBeInserted, element.nextSibling);
  837. }
  838.  
  839. function generateUniqueId() {
  840. let currentDate = new Date();
  841. return (
  842. currentDate.getFullYear() +
  843. "-" +
  844. (currentDate.getMonth() + 1) +
  845. "-" +
  846. currentDate.getDate() +
  847. "_" +
  848. currentDate.getHours() +
  849. "-" +
  850. currentDate.getMinutes() +
  851. "-" +
  852. currentDate.getSeconds() +
  853. "_" +
  854. Math.random().toString(36).substring(2, 15)
  855. );
  856. }
  857.  
  858. function isSoccerTacticsPage() {
  859. return document.getElementById("tactics_box").classList.contains("soccer");
  860. }
  861. })();