diff --git a/src/main.js b/src/main.js index 9526ceb..0fa569e 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,5 @@ -const fx_version = '0.6.6.3'; // FX Client Version -const fx_update = 'Oct 21'; // FX Client Last Updated +const fx_version = '0.6.6.4'; // FX Client Version +const fx_update = 'Oct 26'; // FX Client Last Updated import settingsManager from './settings.js'; import { clanFilter, leaderboardFilter } from "./clanFilters.js"; @@ -29,4 +29,4 @@ __fx.clanFilter = clanFilter; __fx.wins = winCounter; __fx.customLobby = customLobby; -console.log('Successfully loaded FX Client'); \ No newline at end of file +console.log('Successfully loaded FX Client'); diff --git a/src/settings.js b/src/settings.js index a74575b..966f915 100644 --- a/src/settings.js +++ b/src/settings.js @@ -6,204 +6,293 @@ window.__fx = window.__fx || {}; const __fx = window.__fx; var settings = { - //"fontName": "Trebuchet MS", - //"showBotDonations": false, - "displayWinCounter": true, - "useFullscreenMode": false, - "hoveringTooltip": true, - //"hideAllLinks": false, - "realisticNames": false, - "showPlayerDensity": true, - "coloredDensity": true, - "densityDisplayStyle": "percentage", - "highlightClanSpawns": false, - //"customMapFileBtn": true - "customBackgroundUrl": "", - "attackPercentageKeybinds": [], + //"fontName": "Trebuchet MS", + //"showBotDonations": false, + displayWinCounter: true, + useFullscreenMode: false, + hoveringTooltip: true, + //"hideAllLinks": false, + realisticNames: false, + showPlayerDensity: true, + coloredDensity: true, + densityDisplayStyle: "percentage", + highlightClanSpawns: false, + //"customMapFileBtn": true + customBackgroundUrl: "", + attackPercentageKeybinds: [], }; __fx.settings = settings; -const discontinuedSettings = [ "hideAllLinks", "fontName" ]; +const discontinuedSettings = ["hideAllLinks", "fontName"]; __fx.makeMainMenuTransparent = false; /*var settingsGearIcon = document.createElement('img'); settingsGearIcon.setAttribute('src', 'assets/geari_white.png');*/ -const settingsManager = new (function() { - const settingsStructure = [ - { for: "displayWinCounter", type: "checkbox", label: "Display win counter", - note: "The win counter tracks multiplayer solo wins (not in team games)" }, - { type: "button", text: "Reset win counter", action: winCounter.removeWins }, - { for: "useFullscreenMode", type: "checkbox", label: "Use fullscreen mode", - note: "Note: fullscreen mode will trigger after you click anywhere on the page due to browser policy restrictions." }, - { for: "hoveringTooltip", type: "checkbox", label: "Hovering tooltip", - note: "Display map territory info constantly (on mouse hover) instead of only when right clicking on the map" }, - //{ for: "hideAllLinks", type: "checkbox", label: "Hide Links option also hides app store links" }, - { for: "realisticNames", type: "checkbox", label: "Realistic Bot Names" }, - { for: "showPlayerDensity", type: "checkbox", label: "Show player density" }, - { for: "coloredDensity", type: "checkbox", label: "Colored density", note: "Display the density with a color between red and green depending on the density value" }, - { for: "densityDisplayStyle", type: "selectMenu", label: "Density value display style:", tooltip: "Controls how the territorial density value should be rendered", options: [ - { value: "percentage", label: "Percentage" }, - { value: "absoluteQuotient", label: "Value from 0 to 150 (BetterTT style)" } - ]}, - { for: "highlightClanSpawns", type: "checkbox", label: "Highlight clan spawnpoints", - note: "Increases the spawnpoint glow size for members of your clan" }, - { for: "customBackgroundUrl", type: "textInput", label: "Custom main menu background:", placeholder: "Enter an image URL here", tooltip: "A custom image to be shown as the main menu background instead of the currently selected map." }, - KeybindsInput - ]; - const settingsContainer = document.querySelector(".settings .scrollable"); - var inputFields = {}; // (includes select menus) - var checkboxFields = {}; - var customElements = []; - settingsStructure.forEach(item => { - if (typeof item === "function") { - const container = document.createElement("div"); - customElements.push(new item(container)); - return settingsContainer.append(container); - } - const label = document.createElement("label"); - if (item.tooltip) label.title = item.tooltip; - const isValueInput = item.type.endsWith("Input"); - const element = document.createElement(isValueInput || item.type === "checkbox" ? "input" : item.type === "selectMenu" ? "select" : "button"); - if (item.type === "textInput") element.type = "text"; - if (item.placeholder) element.placeholder = item.placeholder; - if (isValueInput || item.type === "selectMenu") inputFields[item.for] = element; - if (item.text) element.innerText = item.text; - if (item.action) element.addEventListener("click", item.action); - if (item.label) label.append(item.label + " "); - if (item.note) { - const note = document.createElement("small"); - note.innerText = item.note; - label.append(document.createElement("br"), note) - } - if (item.options) item.options.forEach(option => { - const optionElement = document.createElement("option"); - optionElement.setAttribute("value", option.value); - optionElement.innerText = option.label; - element.append(optionElement); - }); - label.append(element); - if (item.type === "checkbox") { - element.type = "checkbox"; - const checkmark = document.createElement("span"); - checkmark.className = "checkmark"; - label.className = "checkbox"; - label.append(checkmark); - checkboxFields[item.for] = element; - } else label.append(document.createElement("br")); - settingsContainer.append(label, document.createElement("br")); +const settingsManager = new (function () { + const settingsStructure = [ + { + for: "displayWinCounter", + type: "checkbox", + label: "Display win counter", + note: "The win counter tracks multiplayer solo wins (not in team games)", + }, + { + type: "button", + text: "Reset win counter", + action: winCounter.removeWins, + }, + { + for: "useFullscreenMode", + type: "checkbox", + label: "Use fullscreen mode", + note: "Note: fullscreen mode will trigger after you click anywhere on the page due to browser policy restrictions.", + }, + { + for: "hoveringTooltip", + type: "checkbox", + label: "Hovering tooltip", + note: "Display map territory info constantly (on mouse hover) instead of only when right clicking on the map", + }, + //{ for: "hideAllLinks", type: "checkbox", label: "Hide Links option also hides app store links" }, + { for: "realisticNames", type: "checkbox", label: "Realistic Bot Names" }, + { + for: "showPlayerDensity", + type: "checkbox", + label: "Show player density", + }, + { + for: "coloredDensity", + type: "checkbox", + label: "Colored density", + note: "Display the density with a color between red and green depending on the density value", + }, + { + for: "densityDisplayStyle", + type: "selectMenu", + label: "Density value display style:", + tooltip: "Controls how the territorial density value should be rendered", + options: [ + { value: "percentage", label: "Percentage" }, + { + value: "absoluteQuotient", + label: "Value from 0 to 150 (BetterTT style)", + }, + ], + }, + { + for: "highlightClanSpawns", + type: "checkbox", + label: "Highlight clan spawnpoints", + note: "Increases the spawnpoint glow size for members of your clan", + }, + { + for: "customBackgroundUrl", + type: "textInput", + label: "Custom main menu background:", + placeholder: "Enter an image URL here", + tooltip: + "A custom image to be shown as the main menu background instead of the currently selected map.", + }, + KeybindsInput, + ]; + const settingsContainer = document.querySelector(".settings .scrollable"); + var inputFields = {}; // (includes select menus) + var checkboxFields = {}; + var customElements = []; + settingsStructure.forEach((item) => { + if (typeof item === "function") { + const container = document.createElement("div"); + customElements.push(new item(container)); + return settingsContainer.append(container); + } + const label = document.createElement("label"); + if (item.tooltip) label.title = item.tooltip; + const isValueInput = item.type.endsWith("Input"); + const element = document.createElement( + isValueInput || item.type === "checkbox" + ? "input" + : item.type === "selectMenu" + ? "select" + : "button" + ); + if (item.type === "textInput") element.type = "text"; + if (item.placeholder) element.placeholder = item.placeholder; + if (isValueInput || item.type === "selectMenu") + inputFields[item.for] = element; + if (item.text) element.innerText = item.text; + if (item.action) element.addEventListener("click", item.action); + if (item.label) label.append(item.label + " "); + if (item.note) { + const note = document.createElement("small"); + note.innerText = item.note; + label.append(document.createElement("br"), note); + } + if (item.options) + item.options.forEach((option) => { + const optionElement = document.createElement("option"); + optionElement.setAttribute("value", option.value); + optionElement.innerText = option.label; + element.append(optionElement); + }); + label.append(element); + if (item.type === "checkbox") { + element.type = "checkbox"; + const checkmark = document.createElement("span"); + checkmark.className = "checkmark"; + label.className = "checkbox"; + label.append(checkmark); + checkboxFields[item.for] = element; + } else label.append(document.createElement("br")); + settingsContainer.append(label, document.createElement("br")); + }); + this.save = function () { + Object.keys(inputFields).forEach(function (key) { + settings[key] = inputFields[key].value.trim(); }); - this.save = function() { - Object.keys(inputFields).forEach(function(key) { settings[key] = inputFields[key].value.trim(); }); - Object.keys(checkboxFields).forEach(function(key) { settings[key] = checkboxFields[key].checked; }); - this.applySettings(); - WindowManager.closeWindow("settings"); - discontinuedSettings.forEach(settingName => delete settings[settingName]); + Object.keys(checkboxFields).forEach(function (key) { + settings[key] = checkboxFields[key].checked; + }); + this.applySettings(); + WindowManager.closeWindow("settings"); + discontinuedSettings.forEach((settingName) => delete settings[settingName]); + localStorage.setItem("fx_settings", JSON.stringify(settings)); + // should probably firgure out a way to do this without reloading - // You can't do it, localstorages REQUIRE you to reload + window.location.reload(); + }; + + const fileInput = document.createElement("input"); + fileInput.type = "file"; + function handleFileSelect(event) { + const input = event.target; + /** @type {File} */ + const selectedFile = input.files[0]; + if (!selectedFile) return; + + input.removeEventListener("change", handleFileSelect); + input.value = ""; + if (!selectedFile.name.endsWith(".json")) + return alert("Invalid file format"); + const fileReader = new FileReader(); + fileReader.onload = function () { + let result; + try { + result = JSON.parse(fileReader.result); + if ( + confirm( + 'Warning: This will override all current settings, click "OK" to confirm' + ) + ) + __fx.settings = settings = result; localStorage.setItem("fx_settings", JSON.stringify(settings)); - // should probably firgure out a way to do this without reloading - // You can't do it, localstorages REQUIRE you to reload window.location.reload(); + } catch (error) { + alert("Error\n" + error); + } }; + fileReader.readAsText(selectedFile); + } + this.importFromFile = function () { + fileInput.click(); + fileInput.addEventListener("change", handleFileSelect); + }; + // https://stackoverflow.com/a/34156339 + function saveFile(content, fileName, contentType) { + var a = document.createElement("a"); + var file = new Blob([content], { type: contentType }); + a.href = URL.createObjectURL(file); + a.download = fileName; + a.click(); + URL.revokeObjectURL(a.href); + } + this.exportToFile = function () { + saveFile( + JSON.stringify(settings), + "FX_client_settings.json", + "application/json" + ); + }; - const fileInput = document.createElement("input"); - fileInput.type = "file"; - function handleFileSelect(event) { - const input = event.target; - /** @type {File} */ - const selectedFile = input.files[0]; - if (!selectedFile) return; + this.syncFields = function () { + Object.keys(inputFields).forEach(function (key) { + inputFields[key].value = settings[key]; + }); + Object.keys(checkboxFields).forEach(function (key) { + checkboxFields[key].checked = settings[key]; + }); + customElements.forEach((element) => element.update(settings)); + }; + this.resetAll = function () { + if ( + !confirm( + "Are you Really SURE you want to RESET ALL SETTINGS back to the default?" + ) + ) + return; + localStorage.removeItem("fx_settings"); + window.location.reload(); + }; + this.applySettings = function () { + //setVarByName("bu", "px " + settings.fontName); - input.removeEventListener("change", handleFileSelect); - input.value = ""; - if (!selectedFile.name.endsWith(".json")) return alert("Invalid file format"); - const fileReader = new FileReader(); - fileReader.onload = function() { - let result; - try { - result = JSON.parse(fileReader.result); - if (confirm("Warning: This will override all current settings, click \"OK\" to confirm")) __fx.settings = settings = result; - localStorage.setItem("fx_settings", JSON.stringify(settings)); - window.location.reload(); - } catch (error) { - alert("Error\n" + error) - } - } - fileReader.readAsText(selectedFile); + if (settings.customBackgroundUrl !== "") { + document.body.style.backgroundImage = + "url(" + settings.customBackgroundUrl + ")"; + document.body.style.backgroundSize = "cover"; + document.body.style.backgroundPosition = "center"; } - this.importFromFile = function() { - fileInput.click(); - fileInput.addEventListener('change', handleFileSelect); - }; - // https://stackoverflow.com/a/34156339 - function saveFile(content, fileName, contentType) { - var a = document.createElement("a"); - var file = new Blob([content], {type: contentType}); - a.href = URL.createObjectURL(file); - a.download = fileName; - a.click(); - URL.revokeObjectURL(a.href); - } - this.exportToFile = function() { - saveFile(JSON.stringify(settings), 'FX_client_settings.json', 'application/json'); - }; + __fx.makeMainMenuTransparent = settings.customBackgroundUrl !== ""; + }; - this.syncFields = function() { - Object.keys(inputFields).forEach(function(key) { inputFields[key].value = settings[key]; }); - Object.keys(checkboxFields).forEach(function(key) { checkboxFields[key].checked = settings[key]; }); - customElements.forEach(element => element.update(settings)); - }; - this.resetAll = function() { - if (!confirm("Are you Really SURE you want to RESET ALL SETTINGS back to the default?")) return; - localStorage.removeItem("fx_settings"); - window.location.reload(); - }; - this.applySettings = function() { - //setVarByName("bu", "px " + settings.fontName); - if (settings.useFullscreenMode && document.fullscreenEnabled) { - function tryEnterFullscreen() { - if (document.fullscreenElement !== null) return; - document.documentElement.requestFullscreen({ navigationUI: "hide" }) - .then(() => { console.log('Fullscreen mode activated'); }) - .catch((error) => { console.warn('Could not enter fullscreen mode:', error); }); - } - document.addEventListener('mousedown', tryEnterFullscreen, { once: true }); - document.addEventListener('click', tryEnterFullscreen, { once: true }); - } - if (settings.customBackgroundUrl !== "") { - document.body.style.backgroundImage = "url(" + settings.customBackgroundUrl + ")"; - document.body.style.backgroundSize = "cover"; - document.body.style.backgroundPosition = "center"; - } - __fx.makeMainMenuTransparent = settings.customBackgroundUrl !== ""; - }; -}); + if (settings.useFullscreenMode) tryEnterFullscreen(); +})(); + +export function tryEnterFullscreen() { + if (document.fullscreenElement !== null || !document.fullscreenEnabled) return; + document.documentElement + .requestFullscreen({ navigationUI: "hide" }) + .then(() => { + console.log("Fullscreen mode activated"); + }) + .catch((error) => { + console.warn("Could not enter fullscreen mode:", error); + }); +} const openCustomBackgroundFilePicker = () => { - const fileInput = document.getElementById("customBackgroundFileInput"); - fileInput.click(); - fileInput.addEventListener('change', handleFileSelect); -} + const fileInput = document.getElementById("customBackgroundFileInput"); + fileInput.click(); + fileInput.addEventListener("change", handleFileSelect); +}; function handleFileSelect(event) { - const fileInput = event.target; - const selectedFile = fileInput.files[0]; - console.log(fileInput.files); - console.log(fileInput.files[0]); - if (selectedFile) { - const fileUrl = URL.createObjectURL(selectedFile); - console.log("File URL:", fileUrl); - fileInput.value = ""; - fileInput.removeEventListener("change", handleFileSelect); - } + const fileInput = event.target; + const selectedFile = fileInput.files[0]; + console.log(fileInput.files); + console.log(fileInput.files[0]); + if (selectedFile) { + const fileUrl = URL.createObjectURL(selectedFile); + console.log("File URL:", fileUrl); + fileInput.value = ""; + fileInput.removeEventListener("change", handleFileSelect); + } } WindowManager.add({ - name: "settings", - element: document.querySelector(".settings"), - beforeOpen: function() { settingsManager.syncFields(); } + name: "settings", + element: document.querySelector(".settings"), + beforeOpen: function () { + settingsManager.syncFields(); + }, }); if (localStorage.getItem("fx_settings") !== null) { - __fx.settings = settings = {...settings, ...JSON.parse(localStorage.getItem("fx_settings"))}; + __fx.settings = settings = { + ...settings, + ...JSON.parse(localStorage.getItem("fx_settings")), + }; } settingsManager.applySettings(); export default settingsManager; -export function getSettings() { return settings; }; \ No newline at end of file +export function getSettings() { + return settings; +} diff --git a/src/windowManager.js b/src/windowManager.js index 95ef9f4..20930c5 100644 --- a/src/windowManager.js +++ b/src/windowManager.js @@ -1,40 +1,63 @@ +import { getSettings, tryEnterFullscreen } from "./settings.js"; + var windows = {}; + const container = document.getElementById("windowContainer"); function create(info) { - const window = document.createElement("div"); - info.element = window; - window.className = "window" + (info.classes !== undefined ? " " + info.classes : " scrollable selectable"); - window.style.display = "none"; - container.appendChild(window); - add(info); - return window; + const window = document.createElement("div"); + info.element = window; + window.className = + "window" + + (info.classes !== undefined + ? " " + info.classes + : " scrollable selectable"); + window.style.display = "none"; + container.appendChild(window); + add(info); + return window; } function add(newWindow) { - windows[newWindow.name] = newWindow; - windows[newWindow.name].isOpen = false; -}; + windows[newWindow.name] = newWindow; + windows[newWindow.name].isOpen = false; +} function openWindow(windowName, ...args) { - if (windows[windowName].isOpen === true) return; - if (windows[windowName].beforeOpen !== undefined) windows[windowName].beforeOpen(...args); - windows[windowName].isOpen = true; - windows[windowName].element.style.display = null; -}; + if (windows[windowName].isOpen === true) return; + if (windows[windowName].beforeOpen !== undefined) + windows[windowName].beforeOpen(...args); + windows[windowName].isOpen = true; + windows[windowName].element.style.display = null; +} function closeWindow(windowName) { - if (windows[windowName].isOpen === false) return; - windows[windowName].isOpen = false; - windows[windowName].element.style.display = "none"; - if (windows[windowName].onClose !== undefined) windows[windowName].onClose(); -}; + if (windows[windowName].isOpen === false) return; + windows[windowName].isOpen = false; + windows[windowName].element.style.display = "none"; + if (windows[windowName].onClose !== undefined) windows[windowName].onClose(); +} function closeAll() { - Object.values(windows).forEach(function (windowObj) { - if (windowObj.closable !== false) closeWindow(windowObj.name); - }); -}; -document.addEventListener("mousedown", (e) => { + Object.values(windows).forEach(function (windowObj) { + if (windowObj.closable !== false) closeWindow(windowObj.name); + }); +} +document.addEventListener( + "mousedown", + (e) => { // when clicking outside a window if (!container.contains(e.target)) closeAll(); -}, { passive: true, capture: true }) -document.getElementById("canvasA").addEventListener("touchstart", closeAll, { passive: true }); -document.addEventListener("keydown", event => { if (event.key === "Escape") closeAll(); }); -export default { create, add, openWindow, closeWindow, closeAll } \ No newline at end of file + const isFullScreenEnabled = getSettings().useFullscreenMode; + + if (isFullScreenEnabled) { + tryEnterFullscreen(); + } + }, + { passive: true, capture: true } +); + +document + .getElementById("canvasA") + .addEventListener("touchstart", closeAll, { passive: true }); +document.addEventListener("keydown", (event) => { + if (event.key === "Escape") closeAll(); +}); + +export default { create, add, openWindow, closeWindow, closeAll };