From 9f7a4cf5a7ff45ebad524aa7ec6edc60cd84cfb1 Mon Sep 17 00:00:00 2001 From: 0neGal Date: Fri, 31 May 2024 16:14:12 +0200 Subject: fixed error when enabledmods.json cant be parsed --- src/modules/mods.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/mods.js b/src/modules/mods.js index 169e7b1..6214098 100644 --- a/src/modules/mods.js +++ b/src/modules/mods.js @@ -350,6 +350,10 @@ mods.modfile.get = (mod) => { // read enabledmods.json let data = json(mods.modfile.file); + if (! data || typeof data !== "object") { + return true; + } + if (data[mod]) { // enabled return true; } else if (data[mod] === false) { // disabled -- cgit v1.2.3 From dbd8c6b152acc1188d2edd288488aa2da8f6310b Mon Sep 17 00:00:00 2001 From: 0neGal Date: Sat, 8 Jun 2024 18:02:48 +0200 Subject: initial commit to better modularize frontend Far from done, but this pretty much splits everything inside `src/app/main.js` into separate files. --- src/app/css/theming.css | 2 +- src/app/index.html | 42 ++-- src/app/js/browser.js | 40 +-- src/app/js/dom_events.js | 42 ++++ src/app/js/events.js | 2 + src/app/js/gamepath.js | 51 ++++ src/app/js/is_running.js | 46 ++++ src/app/js/kill.js | 8 + src/app/js/launch.js | 15 ++ src/app/js/launcher.js | 9 +- src/app/js/mods.js | 95 ++++++- src/app/js/popups.js | 6 +- src/app/js/process.js | 27 ++ src/app/js/request.js | 18 ++ src/app/js/set_buttons.js | 40 +++ src/app/js/set_dom_strings.js | 19 ++ src/app/js/settings.js | 529 ++++++++++++++++++++++++--------------- src/app/js/update.js | 145 +++++++++++ src/app/lang.js | 19 -- src/app/main.js | 557 ++---------------------------------------- src/modules/kill.js | 10 +- 21 files changed, 908 insertions(+), 814 deletions(-) create mode 100644 src/app/js/dom_events.js create mode 100644 src/app/js/gamepath.js create mode 100644 src/app/js/is_running.js create mode 100644 src/app/js/kill.js create mode 100644 src/app/js/launch.js create mode 100644 src/app/js/process.js create mode 100644 src/app/js/request.js create mode 100644 src/app/js/set_buttons.js create mode 100644 src/app/js/set_dom_strings.js create mode 100644 src/app/js/update.js delete mode 100644 src/app/lang.js diff --git a/src/app/css/theming.css b/src/app/css/theming.css index aff3782..fb8fbf7 100644 --- a/src/app/css/theming.css +++ b/src/app/css/theming.css @@ -37,7 +37,7 @@ a { transition: filter 0.2s ease-in !important; } -a.disabled:not("[onclick='kill_game()']") { +a.disabled:not("[onclick='kill('game')']") { opacity: 0.5; pointer-events: none; } diff --git a/src/app/index.html b/src/app/index.html index 016b708..87a1029 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -12,7 +12,7 @@
-
+
@@ -34,11 +34,11 @@
-
@@ -147,9 +147,9 @@
- - - + + +
@@ -181,12 +181,12 @@
- - - - - - + + + + + +
@@ -247,7 +247,7 @@ @@ -277,10 +277,10 @@
- +
@@ -298,7 +298,7 @@ %%gui.mods.toggle_all%% - @@ -320,10 +320,11 @@
- +
@@ -331,16 +332,13 @@
- - - diff --git a/src/app/js/browser.js b/src/app/js/browser.js index 06dc244..00a0933 100644 --- a/src/app/js/browser.js +++ b/src/app/js/browser.js @@ -98,7 +98,7 @@ var Browser = { } }, install: (package_obj, clear_queue = false) => { - return installFromURL( + return mods.install_from_url( package_obj.download || package_obj.versions[0].download_url, package_obj.dependencies || package_obj.versions[0].dependencies, clear_queue, @@ -119,9 +119,9 @@ var Browser = { let remote_version = packages[i].versions[0].version_number; remote_version = version.format(remote_version); - if (modsobj) { - for (let ii = 0; ii < modsobj.all.length; ii++) { - let mod = modsobj.all[ii]; + if (mods.list()) { + for (let ii = 0; ii < mods.list().all.length; ii++) { + let mod = mods.list().all[ii]; if (normalize(mod.name) !== normalized && ( ! mod.package || @@ -288,14 +288,14 @@ var Browser = { } setTimeout(() => { - for (let i = 0; i < modsobj.all.length; i++) { - let modname = normalize(modsobj.all[i].name); - let modfolder = normalize(modsobj.all[i].folder_name); + for (let i = 0; i < mods.list().all.length; i++) { + let modname = normalize(mods.list().all[i].name); + let modfolder = normalize(mods.list().all[i].folder_name); if (mod.includes(modname)) { if (! make(modname)) { - if (modsobj.all[i].manifest_name) { - make(normalize(modsobj.all[i].manifest_name)); + if (mods.list().all[i].manifest_name) { + make(normalize(mods.list().all[i].manifest_name)); } } } @@ -405,7 +405,7 @@ function BrowserEl(properties) { let installstr = lang("gui.browser.install"); let normalized_mods = []; - for (let i = 0; i < modsobj.all; i++) { + for (let i = 0; i < mods.list().all; i++) { normalized_mods.push(normalize(mods_list[i].name)); } @@ -467,7 +467,7 @@ function add_recent_toast(name, timeout = 3000) { } ipcRenderer.on("removed-mod", (event, mod) => { - setButtons(true); + set_buttons(true); Browser.setbutton(mod.name, lang("gui.browser.install"), "downloads"); if (mod.manifest_name) { @@ -479,7 +479,7 @@ ipcRenderer.on("failed-mod", (event, modname) => { if (recent_toasts["failed" + modname]) {return} add_recent_toast("failed" + modname); - setButtons(true); + set_buttons(true); new Toast({ timeout: 10000, scheme: "error", @@ -492,7 +492,7 @@ ipcRenderer.on("legacy-duped-mod", (event, modname) => { if (recent_toasts["duped" + modname]) {return} add_recent_toast("duped" + modname); - setButtons(true); + set_buttons(true); new Toast({ timeout: 10000, scheme: "warning", @@ -502,7 +502,7 @@ ipcRenderer.on("legacy-duped-mod", (event, modname) => { }) ipcRenderer.on("no-internet", (event, modname) => { - setButtons(true); + set_buttons(true); new Toast({ timeout: 10000, scheme: "error", @@ -517,7 +517,7 @@ ipcRenderer.on("installed-mod", (event, mod) => { let name = mod.fancy_name || mod.name; - setButtons(true); + set_buttons(true); Browser.setbutton(name, lang("gui.browser.reinstall"), "redo"); if (mod.malformed) { @@ -535,13 +535,13 @@ ipcRenderer.on("installed-mod", (event, mod) => { description: name + " " + lang("gui.toast.desc.installed") }) - if (installqueue.length != 0) { - installFromURL( - "https://thunderstore.io/package/download/" + installqueue[0].pkg, - false, false, installqueue[0].author, installqueue[0].package_name, installqueue[0].version + if (mods.install_queue.length != 0) { + mods.install_from_url( + "https://thunderstore.io/package/download/" + mods.install_queue[0].pkg, + false, false, mods.install_queue[0].author, mods.install_queue[0].package_name, mods.install_queue[0].version ) - installqueue.shift(); + mods.install_queue.shift(); } }) diff --git a/src/app/js/dom_events.js b/src/app/js/dom_events.js new file mode 100644 index 0000000..73e9998 --- /dev/null +++ b/src/app/js/dom_events.js @@ -0,0 +1,42 @@ +const settings = require("./settings"); + +let drag_timer; +document.addEventListener("dragover", (e) => { + e.preventDefault(); + e.stopPropagation(); + dragUI.classList.add("shown"); + + clearTimeout(drag_timer); + drag_timer = setTimeout(() => { + dragUI.classList.remove("shown"); + }, 5000) +}) + +document.addEventListener("mouseover", () => { + clearTimeout(drag_timer); + dragUI.classList.remove("shown"); +}) + +document.addEventListener("drop", (e) => { + e.preventDefault(); + e.stopPropagation(); + + dragUI.classList.remove("shown"); + mods.install_from_path(e.dataTransfer.files[0].path); +}) + +document.body.addEventListener("keyup", (e) => { + if (e.key == "Escape") { + Browser.toggle(false); + settings.popup.toggle(false); + } +}) + +document.body.addEventListener("click", (e) => { + if (e.target.tagName.toLowerCase() === "a" + && e.target.protocol != "file:") { + + e.preventDefault(); + shell.openExternal(e.target.href); + } +}) diff --git a/src/app/js/events.js b/src/app/js/events.js index cced4a7..040382e 100644 --- a/src/app/js/events.js +++ b/src/app/js/events.js @@ -1,3 +1,5 @@ const EventEmitter = require("events"); class Emitter extends EventEmitter {}; const events = new Emitter(); + +module.exports = events; diff --git a/src/app/js/gamepath.js b/src/app/js/gamepath.js new file mode 100644 index 0000000..80e3158 --- /dev/null +++ b/src/app/js/gamepath.js @@ -0,0 +1,51 @@ +const ipcRenderer = require("electron").ipcRenderer; + +const lang = require("../../lang"); +const process = require("./process"); +const settings = require("./settings"); + +// frontend part of settings a new game path +ipcRenderer.on("newpath", (_, newpath) => { + set_buttons(true); + + settings.set({gamepath: newpath}); + + ipcRenderer.send("gui-getmods"); + ipcRenderer.send("save-settings", settings.data()); +}) + +// a previously valid gamepath no longer exists, and is therefore lost +ipcRenderer.on("gamepath-lost", () => { + page(0); + set_buttons(false, true); + alert(lang("gui.gamepath.lost")); +}) + +// error out when no game path is set +ipcRenderer.on("no-path-selected", () => { + alert(lang("gui.gamepath.must")); + process.exit(); +}) + +// error out when game path is wrong +ipcRenderer.on("wrong-path", () => { + alert(lang("gui.gamepath.wrong")); + gamepath.set(false); +}) + +// reports to the main process about game path status. +module.exports = { + open: () => { + let gamepath = settings.data().gamepath; + + if (gamepath) { + require("electron").shell.openPath(gamepath); + } else { + alert(lang("gui.settings.miscbuttons.open_gamepath_alert")); + } + }, + + set: (value) => { + ipcRenderer.send("setpath", value); + } +} diff --git a/src/app/js/is_running.js b/src/app/js/is_running.js new file mode 100644 index 0000000..69efd5b --- /dev/null +++ b/src/app/js/is_running.js @@ -0,0 +1,46 @@ +const lang = require("../../lang"); + +// is the game running? +let is_running = false; + +// updates play buttons depending on whether the game is running +ipcRenderer.on("is-running", (event, running) => { + let set_playbtns = (text) => { + let playbtns = document.querySelectorAll(".playBtn"); + for (let i = 0; i < playbtns.length; i++) { + playbtns[i].innerHTML = text; + } + } + + if (running && is_running != running) { + set_buttons(false); + set_playbtns(lang("general.running")); + + is_running = running; + + // show force quit button in Titanfall tab + tfquit.style.display = "inline-block"; + + update.setAttribute("onclick", "kill('game')"); + update.innerHTML = "(" + lang("ns.menu.force_quit") + ")"; + return; + } + + if (is_running != running) { + set_buttons(true); + set_playbtns(lang("gui.launch")); + + is_running = running; + + // hide force quit button in Titanfall tab + tfquit.style.display = "none"; + + update.setAttribute("onclick", "update.ns()"); + update.innerHTML = "(" + lang("gui.update.check") + ")"; + } +}) + +// return whether the game is running +module.exports = () => { + return is_running; +} diff --git a/src/app/js/kill.js b/src/app/js/kill.js new file mode 100644 index 0000000..04f0a84 --- /dev/null +++ b/src/app/js/kill.js @@ -0,0 +1,8 @@ +const ipcRenderer = require("electron").ipcRenderer; + +// attempts to kill something using the main process' `modules/kill.js` +// functions, it simply attempts to run `kill[function_name]()`, if it +// doesn't exist, nothing happens +module.exports = (function_name) => { + ipcRenderer.send("kill", function_name); +} diff --git a/src/app/js/launch.js b/src/app/js/launch.js new file mode 100644 index 0000000..d14d2ee --- /dev/null +++ b/src/app/js/launch.js @@ -0,0 +1,15 @@ +const update = require("./update"); + +// tells the main process to launch `game_version` +module.exports = (game_version) => { + if (game_version == "vanilla") { + ipcRenderer.send("launch", game_version); + return; + } + + if (update.ns.should_install) { + update.ns(); + } else { + ipcRenderer.send("launch", game_version); + } +} diff --git a/src/app/js/launcher.js b/src/app/js/launcher.js index 1c383b4..6fe1686 100644 --- a/src/app/js/launcher.js +++ b/src/app/js/launcher.js @@ -4,8 +4,7 @@ var servercount; var playercount; var masterserver; -// Changes the main page -// This is the tabs in the sidebar +// changes the main page, this is the tabs in the sidebar function page(page) { let btns = document.querySelectorAll(".gamesContainer button"); let pages = document.querySelectorAll(".mainContainer .contentContainer"); @@ -71,7 +70,7 @@ let set_error_content = (div, lang_key) => { ""; } -// Updates the Viper release notes +// updates the Viper release notes ipcRenderer.on("vp-notes", (event, response) => { if (! response) { return set_error_content( @@ -83,7 +82,7 @@ ipcRenderer.on("vp-notes", (event, response) => { vpReleaseNotes.innerHTML = formatRelease(response); }); -// Updates the Northstar release notes +// updates the Northstar release notes ipcRenderer.on("ns-notes", (event, response) => { if (! response) { return set_error_content( @@ -208,7 +207,7 @@ async function loadServers() { } }; loadServers() -// Refreshes every 5 minutes +// refreshes every 5 minutes setInterval(() => { loadServers(); }, 300000) diff --git a/src/app/js/mods.js b/src/app/js/mods.js index 182bddf..e105c7c 100644 --- a/src/app/js/mods.js +++ b/src/app/js/mods.js @@ -1,4 +1,15 @@ -var mods = {}; +let mods = {}; + +let mods_list = { + all: [], + enabled: [], + disabled: [] +} + +// returns the list of mods +mods.list = () => { + return mods_list; +} mods.load = (mods_obj) => { modcount.innerHTML = `${lang("gui.mods.count")} ${mods_obj.all.length}`; @@ -210,3 +221,85 @@ mods.toggle = (mod) => { ipcRenderer.send("toggle-mod", mod); } + +mods.install_queue = []; + +// tells the main process to install a mod through the file selector +mods.install_prompt = () => { + set_buttons(false); + ipcRenderer.send("install-mod"); +} + +// tells the main process to directly install a mod from this path +mods.install_from_path = (path) => { + set_buttons(false); + ipcRenderer.send("install-from-path", path); +} + +// tells the main process to install a mod from a URL +mods.install_from_url = (url, dependencies, clearqueue, author, package_name, version) => { + if (clearqueue) {mods.install_queue = []}; + + let prettydepends = []; + + if (dependencies) { + let newdepends = []; + for (let i = 0; i < dependencies.length; i++) { + let depend = dependencies[i].toLowerCase(); + if (! depend.match(/northstar-northstar-.*/)) { + depend = dependencies[i].replaceAll("-", "/"); + let pkg = depend.split("/"); + if (! mods.is_installed(pkg[1])) { + newdepends.push({ + pkg: depend, + author: pkg[0], + version: pkg[2], + package_name: pkg[1] + }); + + prettydepends.push(`${pkg[1]} v${pkg[2]} - ${lang("gui.browser.made_by")} ${pkg[0]}`); + } + } + } + + dependencies = newdepends; + } + + if (dependencies && dependencies.length != 0) { + let confirminstall = confirm(lang("gui.mods.confirm_dependencies") + prettydepends.join("\n")); + if (! confirminstall) { + return; + } + } + + set_buttons(false); + ipcRenderer.send("install-from-url", url, author, package_name, version); + + if (dependencies) { + mods.install_queue = dependencies; + } +} + +mods.is_installed = (modname) => { + for (let i = 0; i < mods.list().all.length; i++) { + let mod = mods.list().all[i]; + if (mod.manifest_name) { + if (mod.manifest_name.match(modname)) { + return true; + } + } else if (mod.name.match(modname)) { + return true; + } + } + + return false; +} + + +// updates the installed mods +ipcRenderer.on("mods", (event, mods_obj) => { + mods_list = mods_obj; + if (! mods_obj) {return} + + mods.load(mods_obj); +}) diff --git a/src/app/js/popups.js b/src/app/js/popups.js index 7411180..10c6995 100644 --- a/src/app/js/popups.js +++ b/src/app/js/popups.js @@ -43,7 +43,7 @@ popups.list = () => { return document.querySelectorAll(".popup"); } -popups.set_all = (state, exclude_popup) => { +popups.set_all = (state = false, exclude_popup) => { let popups_list = document.querySelectorAll(".popup.shown"); for (let i = 0; i < popups_list.length; i++) { @@ -51,6 +51,8 @@ popups.set_all = (state, exclude_popup) => { continue; } - popups.set(popups_list[i], false, false); + popups.set(popups_list[i], state, false); } } + +module.exports = popups; diff --git a/src/app/js/process.js b/src/app/js/process.js new file mode 100644 index 0000000..a4aba6c --- /dev/null +++ b/src/app/js/process.js @@ -0,0 +1,27 @@ +const ipcRenderer = require("electron").ipcRenderer; + +ipcRenderer.on("log", (_, msg) => { + console.log(msg) +}) + +ipcRenderer.on("alert", (_, data) => { + alert(data.message); + ipcRenderer.send("alert-closed-" + data.id); +}) + +ipcRenderer.on("confirm", (_, data) => { + let confirmed = confirm(data.message); + ipcRenderer.send("confirm-closed-" + data.id, confirmed); +}) + +module.exports = { + // attempts to relaunch the process + relaunch: () => { + ipcRenderer.send("relaunch"); + }, + + // attempts to exit the process (closing Viper) + exit: () => { + ipcRenderer.send("exit") + } +} diff --git a/src/app/js/request.js b/src/app/js/request.js new file mode 100644 index 0000000..29b8883 --- /dev/null +++ b/src/app/js/request.js @@ -0,0 +1,18 @@ +const ipcRenderer = require("electron").ipcRenderer; + +// show a toast message if no Internet connection has been detected. +if (! navigator.onLine) { + ipcRenderer.send("no-internet"); +} + +// invokes `requests.get()` from `src/modules/requests.js` through the +// main process, and returns the output +let request = async (...args) => { + return await ipcRenderer.invoke("request", ...args); +} + +request.delete_cache = () => { + ipcRenderer.send("delete-request-cache"); +} + +module.exports = request; diff --git a/src/app/js/set_buttons.js b/src/app/js/set_buttons.js new file mode 100644 index 0000000..9cb9d3e --- /dev/null +++ b/src/app/js/set_buttons.js @@ -0,0 +1,40 @@ +const ipcRenderer = require("electron").ipcRenderer; + +ipcRenderer.on("set-buttons", (_, state) => { + set_buttons(state); +}) + +// disables or enables certain buttons when for example +// updating/installing Northstar. +module.exports = (state, enable_gamepath_btns) => { + playNsBtn.disabled = ! state; + + let disable_array = (array) => { + for (let i = 0; i < array.length; i++) { + array[i].disabled = ! state; + + if (state) { + array[i].classList.remove("disabled") + } else { + array[i].classList.add("disabled") + } + } + } + + disable_array(document.querySelectorAll([ + "#modsdiv .el button", + ".disable-when-installing", + ".playBtnContainer .playBtn", + "#nsMods .buttons.modbtns button", + "#browser #browserEntries .text button", + ])) + + if (enable_gamepath_btns) { + let gamepath_btns = query_all('*[onclick="gamepath.set()"]'); + + for (let i = 0; i < gamepath_btns.length; i++) { + gamepath_btns[i].disabled = false; + gamepath_btns[i].classList.remove("disabled"); + } + } +} diff --git a/src/app/js/set_dom_strings.js b/src/app/js/set_dom_strings.js new file mode 100644 index 0000000..000aba4 --- /dev/null +++ b/src/app/js/set_dom_strings.js @@ -0,0 +1,19 @@ +// replaces strings in the HTML will language strings properly. This +// searches for %%%%, aka, %%gui.exit%% will be replaced with +// "Exit", this works without issues. +module.exports = () => { + // finds %%%% strings + html = document.body.innerHTML.split("%%"); + + for (let i = 0; i < html.length; i++) { + // simply checks to make sure it is actually a lang string. + if (html[i][0] != " " && + html[i][html[i].length - 1] != " ") { + // Replaces it with it's string + html[i] = lang(html[i]); + } + } + + // replaces the original HTML with the translated/replaced HTML + document.body.innerHTML = html.join(""); +} diff --git a/src/app/js/settings.js b/src/app/js/settings.js index 2d68c13..93d1c15 100644 --- a/src/app/js/settings.js +++ b/src/app/js/settings.js @@ -1,243 +1,375 @@ -var settings_fuse; +const fs = require("fs"); +const Fuse = require("fuse.js"); +const ipcRenderer = require("electron").ipcRenderer; + +const lang = require("../../lang"); + +const events = require("./events"); +const popups = require("./popups"); + +let settings_fuse; + +// base settings, and future set settings data +let settings_data = { + nsargs: "", + gamepath: "", + nsupdate: true, + autolang: true, + forcedlang: "en", + autoupdate: true, + originkill: false, + zip: "/northstar.zip", + lang: navigator.language, + excludes: [ + "ns_startup_args.txt", + "ns_startup_args_dedi.txt" + ] +} -var Settings = { - toggle: (state) => { - Settings.load(); - options.scrollTo(0, 0); +// loads the settings +if (fs.existsSync("viper.json")) { + let iteration = 0; + + // loads the config file, it's loaded in an interval like this in + // case the config file is currently being written to, if we were to + // read from the file during that, then it'd be empty or similar. + // + // and because of that, we check if the file is empty when loading + // it, if so we wait 100ms, then check again, and we keep doing that + // hoping it'll become normal again. unless we've checked it 50 + // times, then we simply give up, and force the user to re-select + // the gamepath, as this'll make the config file readable again. + // + // ideally it'll never have to check those 50 times, it's only in + // case something terrible has gone awry, like if a write got + // interrupted, or a user messed with the file. + // + // were it to truly be broken, then it'd take up to 5 seconds to + // then reset, this is basically nothing, especially considering + // this should only happen in very rare cases... hopefully! + let config_interval = setInterval(() => { + let gamepath = require("./gamepath"); + + iteration++; + + config = json("viper.json") || {}; + + // checks whether `settings_data.gamepath` is set, and if so, + // it'll attempt to load ns_startup_args.txt + let parse_settings = () => { + // if gamepath is not set, attempt to set it + if (settings_data.gamepath.length === 0) { + gamepath.set(false); + } else { + // if the gamepath is set, we'll simply tell the main + // process about it, and it'll then show the main + // renderer BrowserWindow + gamepath.set(true); + } - popups.set("#options", state); - }, - apply: () => { - settings = {...settings, ...Settings.get()}; - ipcRenderer.send("save-settings", Settings.get()); - }, - get: () => { - let opts = {}; - let options = document.querySelectorAll(".option"); - - for (let i = 0; i < options.length; i++) { - let optName = options[i].getAttribute("name"); - if (options[i].querySelector(".actions input")) { - let input = options[i].querySelector(".actions input").value; - if (options[i].getAttribute("type")) { - opts[optName] = input.split(" "); - } else { - opts[optName] = input; - } - } else if (options[i].querySelector(".actions select")) { - opts[optName] = options[i].querySelector(".actions select").value; - } else if (options[i].querySelector(".actions .switch")) { - if (options[i].querySelector(".actions .switch.on")) { - opts[optName] = true; - } else { - opts[optName] = false; - } + // filepath to Northstar's startup args file + let args = path.join(settings_data.gamepath, "ns_startup_args.txt"); + + // check file exists, and that no `nsargs` setting was set + if (! settings_data.nsargs && fs.existsSync(args)) { + // load arguments from file into `settings` + settings_data.nsargs = fs.readFileSync(args, "utf8") || ""; } } - return opts; + // make sure config isn't empty + if (Object.keys(config).length !== 0) { + // add `config` to `settings` + settings.set(config); + parse_settings(); + + clearInterval(config_interval); + return; + } + + // we've attempted to load the config 50 times now, give up + if (iteration >= 50) { + // request a new gamepath be set + gamepath.set(false); + clearInterval(config_interval); + } + }, 100) +} else { + require("./gamepath").set(); +} + +ipcRenderer.on("changed-settings", (e, new_settings) => { + // attempt to set `settings_data` to `new_settings` + try { + settings.set(new_settings); + }catch(e) {} +}) + +let settings = { + data: () => {return settings_data}, + + // asks the main process to reset the config/settings file + reset: () => { + ipcRenderer.send("reset-config"); }, - load: () => { - // re-opens any closed categories - let categories = document.querySelectorAll("#options details"); - for (let i = 0; i < categories.length; i++) { - categories[i].setAttribute("open", true); + + // merges `object` with `settings_data`, unless `no_merge` is set, + // then it replaces it entirely + set: (object, no_merge) => { + if (no_merge) { + settings_data = object; + return; } - let options = document.querySelectorAll(".option"); + settings_data = { + ...settings_data, + ...object + } + }, - for (let i = 0; i < options.length; i++) { - let optName = options[i].getAttribute("name"); - if (optName == "forcedlang") { - let div = options[i].querySelector("select"); + popup: {} +} - div.innerHTML = ""; - let lang_dir = __dirname + "/../lang"; - let langs = fs.readdirSync(lang_dir); - for (let i in langs) { - let lang_file = require(lang_dir + "/" + langs[i]); - let lang_no_extension = langs[i].replace(/\..*$/, ""); +settings.popup.toggle = (state) => { + settings.popup.load(); + options.scrollTo(0, 0); - if (! lang_file.lang || ! lang_file.lang.title) { - continue; - } + popups.set("#options", state); +} - let title = lang_file.lang.title; +settings.popup.apply = () => { + settings = {...settings, ...settings.popup.get()}; + ipcRenderer.send("save-settings", settings.popup.get()); +} - if (title) { - div.innerHTML += `` - } - - } +settings.popup.get = () => { + let opts = {}; + let options = document.querySelectorAll(".option"); - div.value = settings.forcedlang; - continue; + for (let i = 0; i < options.length; i++) { + let optName = options[i].getAttribute("name"); + if (options[i].querySelector(".actions input")) { + let input = options[i].querySelector(".actions input").value; + if (options[i].getAttribute("type")) { + opts[optName] = input.split(" "); + } else { + opts[optName] = input; } + } else if (options[i].querySelector(".actions select")) { + opts[optName] = options[i].querySelector(".actions select").value; + } else if (options[i].querySelector(".actions .switch")) { + if (options[i].querySelector(".actions .switch.on")) { + opts[optName] = true; + } else { + opts[optName] = false; + } + } + } + + return opts; +} + +settings.popup.load = () => { + // re-opens any closed categories + let categories = document.querySelectorAll("#options details"); + for (let i = 0; i < categories.length; i++) { + categories[i].setAttribute("open", true); + } + + let options = document.querySelectorAll(".option"); + + for (let i = 0; i < options.length; i++) { + let optName = options[i].getAttribute("name"); + if (optName == "forcedlang") { + let div = options[i].querySelector("select"); + + div.innerHTML = ""; + let lang_dir = __dirname + "/../../lang"; + let langs = fs.readdirSync(lang_dir); + for (let i in langs) { + let lang_file = require(lang_dir + "/" + langs[i]); + let lang_no_extension = langs[i].replace(/\..*$/, ""); + + if (! lang_file.lang || ! lang_file.lang.title) { + continue; + } - if (settings[optName] != undefined) { - switch(typeof settings[optName]) { - case "string": - options[i].querySelector(".actions input").value = settings[optName]; - break - case "object": - options[i].querySelector(".actions input").value = settings[optName].join(" "); - break - case "boolean": - let switchDiv = options[i].querySelector(".actions .switch"); - if (settings[optName]) { - switchDiv.classList.add("on"); - switchDiv.classList.remove("off"); - } else { - switchDiv.classList.add("off"); - switchDiv.classList.remove("on"); - } - break + let title = lang_file.lang.title; + if (title) { + div.innerHTML += `` } + } + + div.value = settings_data.forcedlang; + continue; } - // create Fuse based on options from `get_search_arr()` - settings_fuse = new Fuse(get_search_arr(), { - keys: ["text"], - threshold: 0.4, - ignoreLocation: true - }) - - // reset search - Settings.search(); - search_el.value = ""; - - ipcRenderer.send("can-autoupdate"); - ipcRenderer.on("cant-autoupdate", () => { - document.querySelector(".option[name=autoupdate]") - .style.display = "none"; - - document.querySelector(".option[name=autoupdate]") - .setAttribute("perma-hidden", true); - }) - }, - switch: (el, state) => { + if (settings[optName] != undefined) { + switch(typeof settings[optName]) { + case "string": + options[i].querySelector(".actions input").value = settings[optName]; + break + case "object": + options[i].querySelector(".actions input").value = settings[optName].join(" "); + break + case "boolean": + let switchDiv = options[i].querySelector(".actions .switch"); + if (settings[optName]) { + switchDiv.classList.add("on"); + switchDiv.classList.remove("off"); + } else { + switchDiv.classList.add("off"); + switchDiv.classList.remove("on"); + } + break + + } + } + } + + // create Fuse based on options from `get_search_arr()` + settings_fuse = new Fuse(get_search_arr(), { + keys: ["text"], + threshold: 0.4, + ignoreLocation: true + }) + + // reset search + settings.popup.search(); + search_el.value = ""; + + ipcRenderer.send("can-autoupdate"); + ipcRenderer.on("cant-autoupdate", () => { + document.querySelector(".option[name=autoupdate]") + .style.display = "none"; + + document.querySelector(".option[name=autoupdate]") + .setAttribute("perma-hidden", true); + }) +} + +settings.popup.switch = (el, state) => { + if (state) { + return el.classList.add("on"); + } else if (state === false) { + return el.classList.remove("on"); + } + + if (el.classList.contains("switch") && el.tagName == "BUTTON") { + el.classList.toggle("on"); + } +} + +// searches for `query` in the list of options, hides the options +// that dont match, and shows the one that do, if `query` is falsy, +// it'll simply reset everything back to being visible +settings.popup.search = (query = "") => { + // get list of elements that can be hidden + let search_els = [ + ...document.querySelectorAll(".options .title"), + ...document.querySelectorAll(".options .option"), + ...document.querySelectorAll(".options .buttons"), + ...document.querySelectorAll(".options .details"), + ] + + // this sets the visibility of all elements found in + // `search_els` unless the element has the `perma-hidden` + // attribute set + let set_all = (state) => { + // set `state` to the CSS equivalent if (state) { - return el.classList.add("on"); - } else if (state === false) { - return el.classList.remove("on"); + state = null; + } else { + state = "none"; } - if (el.classList.contains("switch") && el.tagName == "BUTTON") { - el.classList.toggle("on"); + // run through elements + for (let i = 0; i < search_els.length; i++) { + // check that the element shouldn't be perma hidden, and + // if so, hide it correctly. + if (search_els[i].hasAttribute("perma-hidden")) { + search_els[i].style.display = "none"; + continue; + } + + // set the visibility + search_els[i].style.display = state; } - }, + } + + // check if `query` is empty, and reset search if so + if (! query || ! query.trim()) { + set_all(true); + } else { + // hide everything + set_all(false); + } - // searches for `query` in the list of options, hides the options - // that dont match, and shows the one that do, if `query` is falsy, - // it'll simply reset everything back to being visible - search: (query = "") => { - // get list of elements that can be hidden - let search_els = [ - ...document.querySelectorAll(".options .title"), - ...document.querySelectorAll(".options .option"), - ...document.querySelectorAll(".options .buttons"), - ...document.querySelectorAll(".options .details"), + // unhides `el` and relevant elements related to it + let unhide = (el) => { + // list of elements that could be relevant through `el`'s + // `.closest()` function + let closest = [ + ".option", + "details", + ".buttons", ] - // this sets the visibility of all elements found in - // `search_els` unless the element has the `perma-hidden` - // attribute set - let set_all = (state) => { - // set `state` to the CSS equivalent - if (state) { - state = null; - } else { - state = "none"; - } + // run through `closest` + for (let i = 0; i < closest.length; i++) { + // shorthand + let closest_el = el.closest(closest[i]); - // run through elements - for (let i = 0; i < search_els.length; i++) { - // check that the element shouldn't be perma hidden, and - // if so, hide it correctly. - if (search_els[i].hasAttribute("perma-hidden")) { - search_els[i].style.display = "none"; - continue; + // was a relevant element found? + if (closest_el) { + // is it supposed to always be hidden? do nothing + if (el.hasAttribute("perma-hidden") + || closest_el.hasAttribute("perma-hidden")) { + + break; } - // set the visibility - search_els[i].style.display = state; - } - } + // reset visibility + closest_el.style.display = null; - // check if `query` is empty, and reset search if so - if (! query || ! query.trim()) { - set_all(true); - } else { - // hide everything - set_all(false); - } - - // unhides `el` and relevant elements related to it - let unhide = (el) => { - // list of elements that could be relevant through `el`'s - // `.closest()` function - let closest = [ - ".option", - "details", - ".buttons", - ] - - // run through `closest` - for (let i = 0; i < closest.length; i++) { - // shorthand - let closest_el = el.closest(closest[i]); - - // was a relevant element found? - if (closest_el) { - // is it supposed to always be hidden? do nothing - if (el.hasAttribute("perma-hidden") - || closest_el.hasAttribute("perma-hidden")) { - - break; - } + // are we at a `
`? + if (closest[i] == "details") { + // attempt to get a `.title` inside that + // `
` element + let title = closest_el.querySelector(".title"); - // reset visibility - closest_el.style.display = null; - - // are we at a `
`? - if (closest[i] == "details") { - // attempt to get a `.title` inside that - // `
` element - let title = closest_el.querySelector(".title"); - - // did we find a title? - if (title) { - // reset visibility of title and also reset - // open state of `
` - title.style.display = null; - closest_el.setAttribute("open", false); - } + // did we find a title? + if (title) { + // reset visibility of title and also reset + // open state of `
` + title.style.display = null; + closest_el.setAttribute("open", false); } } } } + } - // do a Fuse.js search with `query` - let res = settings_fuse.search(query); + // do a Fuse.js search with `query` + let res = settings_fuse.search(query); - // if nothing was found, reset all - if (res.length == 0) { - return set_all(true); - } + // if nothing was found, reset all + if (res.length == 0) { + return set_all(true); + } - // run through results and unhide all of them - for (let i = 0; i < res.length; i++) { - unhide(res[i].item.el); - } + // run through results and unhide all of them + for (let i = 0; i < res.length; i++) { + unhide(res[i].item.el); } } // search on key events in search input let search_el = document.body.querySelector("#options .search"); search_el.addEventListener("keyup", () => { - Settings.search(search_el.value); + settings.popup.search(search_el.value); }) // returns a Fuse.js compatible Array for searching through the settings @@ -337,7 +469,12 @@ events.on("popup-changed", () => { document.body.addEventListener("click", (e) => { let el = document.elementFromPoint(e.clientX, e.clientY); - Settings.switch(el); + settings.popup.switch(el); }) -Settings.load(); +settings.popup.load(); + +// sets the lang to the system default +ipcRenderer.send("setlang", settings_data.lang); + +module.exports = settings; diff --git a/src/app/js/update.js b/src/app/js/update.js new file mode 100644 index 0000000..034f3e8 --- /dev/null +++ b/src/app/js/update.js @@ -0,0 +1,145 @@ +const ipcRenderer = require("electron").ipcRenderer; + +const lang = require("../../lang"); + +// updates version numbers +ipcRenderer.on("version", (event, versions) => { + vpversion.innerText = versions.vp; + nsversion.innerText = versions.ns; + tf2Version.innerText = versions.tf2; + + if (versions.ns == "unknown") { + let buttons = document.querySelectorAll(".modbtns button"); + + for (let i = 0; i < buttons.length; i++) { + buttons[i].disabled = true; + } + + // since Northstar is not installed, we cannot launch it + update.ns.should_install = true; + playNsBtn.innerText = lang("gui.install"); + } +}); ipcRenderer.send("get-version"); + +// when an update is available it'll ask the user about it +ipcRenderer.on("update-available", () => { + if (confirm(lang("gui.update.available"))) { + ipcRenderer.send("update-now"); + } +}) + +// frontend part of updating Northstar +ipcRenderer.on("ns-update-event", (event, options) => { + let key = options.key; + if (typeof options == "string") { + key = options; + } + + // updates text in update button to `lang(key)` + let update_btn = () => { + document.getElementById("update") + .innerText = `(${lang(key)})`; + } + + switch(key) { + case "cli.update.uptodate_short": + case "cli.update.no_internet": + // initial value + let delay = 0; + + // get current time + let now = new Date().getTime(); + + // check if `update.ns.last_checked` was less than 500ms + // since now, this variable is set when `update.ns()` is + // called + if (now - update.ns.last_checked < 500) { + // if less than 500ms has passed, set `delay` to the + // amount of milliseconds missing until we've hit that + // 500ms threshold + delay = 500 - (now - update.ns.last_checked); + } + + // wait `delay`ms + setTimeout(() => { + // set buttons accordingly + update_btn(); + set_buttons(true); + update.ns.progress(false); + playNsBtn.innerText = lang("gui.launch"); + }, delay) + + break; + default: + update_btn(); + + if (options.progress) { + update.ns.progress(options.progress); + } + + if (options.btn_text) { + playNsBtn.innerText = options.btn_text; + } + + set_buttons(false); + break; + } +}) + +let update = { + // deletes install and update cache + delete_cache: () => { + ipcRenderer.send("delete-install-cache"); + }, + + // updates Northstar, `force_update` forcefully updates Northstar, + // causing it to update, even if its already up-to-date + ns: (force_update) => { + update.ns.last_checked = new Date().getTime(); + ipcRenderer.send("update-northstar", force_update); + update.ns.should_install = false; + } +} + +// should Northstar be updated? +update.ns.should_install = false; + +// when was the last time we checked for a Northstar update +update.ns.last_checked = new Date().getTime(); + +// `percent` should be a number between 0 to 100, if it's `false` it'll +// reset it back to nothing instantly, with no animation +update.ns.progress = (percent) => { + // reset button progress + if (percent === false) { + document.querySelector(".contentContainer #nsMain .playBtn") + .style.setProperty("--progress", "unset"); + + return; + } + + percent = parseInt(percent); + + // make sure we're dealing with a number + if (isNaN(percent) || typeof percent !== "number") { + return false; + } + + // limit percent, while this barely has a difference, if you were to + // set a very high number, the CSS would then use a very high + // number, not great. + if (percent > 100) { + percent = 100; + } else if (percent < 0) { + percent = 0; + } + + // invert number to it works in the CSS + percent = 100 - percent; + + // set the CSS progress variable + document.querySelector(".contentContainer #nsMain .playBtn") + .style.setProperty("--progress", percent + "%"); +} + +module.exports = update; diff --git a/src/app/lang.js b/src/app/lang.js deleted file mode 100644 index f1c31d3..0000000 --- a/src/app/lang.js +++ /dev/null @@ -1,19 +0,0 @@ -// Replaces strings in the HTML will language strings properly. This -// searches for %%%%, aka, %%gui.exit%% will be replaced with -// "Exit", this works without issues. -function setlang() { - // Finds %%%% strings - html = document.body.innerHTML.split("%%"); - - for (let i = 0; i < html.length; i++) { - // Simply checks to make sure it is actually a lang string. - if (html[i][0] != " " && - html[i][html[i].length - 1] != " ") { - // Replaces it with it's string - html[i] = lang(html[i]); - } - } - - // Replaces the original HTML with the translated/replaced HTML - document.body.innerHTML = html.join(""); -} diff --git a/src/app/main.js b/src/app/main.js index c3f89d2..2ed3053 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -3,317 +3,7 @@ const path = require("path"); const Fuse = require("fuse.js"); const { app, ipcRenderer, shell } = require("electron"); -const json = require("../modules/json"); - const lang = require("../lang"); -var modsobj = { - all: [], - enabled: [], - disabled: [] -} - -let shouldInstallNorthstar = false; - -// Base settings -var settings = { - nsargs: "", - gamepath: "", - nsupdate: true, - autolang: true, - forcedlang: "en", - autoupdate: true, - originkill: false, - zip: "/northstar.zip", - lang: navigator.language, - excludes: [ - "ns_startup_args.txt", - "ns_startup_args_dedi.txt" - ] -} - -// invokes `requests.get()` from `src/modules/requests.js` through the -// main process, and returns the output -async function request(...args) { - return await ipcRenderer.invoke("request", ...args); -} - -// Sets the lang to the system default -ipcRenderer.send("setlang", settings.lang); - -// Loads the settings -if (fs.existsSync("viper.json")) { - let iteration = 0; - - // loads the config file, it's loaded in an interval like this in - // case the config file is currently being written to, if we were to - // read from the file during that, then it'd be empty or similar. - // - // and because of that, we check if the file is empty when loading - // it, if so we wait 100ms, then check again, and we keep doing that - // hoping it'll become normal again. unless we've checked it 50 - // times, then we simply give up, and force the user to re-select - // the gamepath, as this'll make the config file readable again. - // - // ideally it'll never have to check those 50 times, it's only in - // case something terrible has gone awry, like if a write got - // interrupted, or a user messed with the file. - // - // were it to truly be broken, then it'd take up to 5 seconds to - // then reset, this is basically nothing, especially considering - // this should only happen in very rare cases... hopefully! - let config_interval = setInterval(() => { - iteration++; - - config = json("viper.json") || {}; - - // checks whether `settings.gamepath` is set, and if so, - // it'll attempt to load ns_startup_args.txt - let parse_settings = () => { - // if gamepath is not set, attempt to set it - if (settings.gamepath.length === 0) { - setpath(false); - } else { - // if the gamepath is set, we'll simply tell the main - // process about it, and it'll then show the main - // renderer BrowserWindow - setpath(true); - } - - // filepath to Northstar's startup args file - let args = path.join(settings.gamepath, "ns_startup_args.txt"); - - // check file exists, and that no `nsargs` setting was set - if (! settings.nsargs && fs.existsSync(args)) { - // load arguments from file into `settings` - settings.nsargs = fs.readFileSync(args, "utf8"); - } - } - - // make sure config isn't empty - if (Object.keys(config).length !== 0) { - // add `config` to `settings` - settings = { - ...settings, - ...config - }; parse_settings(); - - clearInterval(config_interval); - return; - } - - // we've attempted to load the config 50 times now, give up - if (iteration >= 50) { - // request a new gamepath be set - setpath(false); - clearInterval(config_interval); - } - }, 100) -} else { - setpath(); -} - -ipcRenderer.on("changed-settings", (e, new_settings) => { - // attempt to set `settings` to `new_settings` - try { - settings = { - ...settings, - ...new_settings - } - }catch(e) {} -}) - -// Show a toast message if no Internet connection has been detected. -if (! navigator.onLine) { - ipcRenderer.send("no-internet"); -} - -function exit() {ipcRenderer.send("exit")} - -let checked_for_ns_update = new Date().getTime(); - -function updateNorthstar() { - checked_for_ns_update = new Date().getTime(); - ipcRenderer.send("update-northstar") -} - -function force_update_ns() { - ipcRenderer.send("update-northstar", true); -} - -function reset_config() { - ipcRenderer.send("reset-config"); -} - -function open_gamepath() { - let open_path = require("electron").shell.openPath; - if (settings.gamepath) { - open_path(settings.gamepath); - } else { - alert(lang("gui.settings.miscbuttons.open_gamepath_alert")); - } -} - -function relaunch() { - ipcRenderer.send("relaunch"); -} - -// Reports to the main process about game path status. -// @param {boolean} value is game path loaded -function setpath(value = false) { - ipcRenderer.send("setpath", value); -} - -// Tells the main process to launch or install Northstar -function launch() { - if (shouldInstallNorthstar) { - updateNorthstar(); - shouldInstallNorthstar = false; - } else { - ipcRenderer.send("launch-ns"); - } -} - -// Tells the main process to launch the vanilla game -function launchVanilla() {ipcRenderer.send("launch-vanilla")} - -let log = console.log; - -// Disables or enables certain buttons when for example -// updating/installing Northstar. -function setButtons(state, enable_gamepath_btns) { - playNsBtn.disabled = !state; - - let disablearray = (array) => { - for (let i = 0; i < array.length; i++) { - array[i].disabled = ! state; - - if (state) { - array[i].classList.remove("disabled") - } else { - array[i].classList.add("disabled") - } - } - } - - disablearray(document.querySelectorAll("#modsdiv .el button")); - disablearray(document.querySelectorAll(".disable-when-installing")); - disablearray(document.querySelectorAll(".playBtnContainer .playBtn")); - disablearray(document.querySelectorAll("#nsMods .buttons.modbtns button")); - disablearray(document.querySelectorAll("#browser #browserEntries .text button")); - - if (enable_gamepath_btns) { - let gamepath_btns = - document.querySelectorAll('*[onclick="setpath()"]'); - - for (let i = 0; i < gamepath_btns.length; i++) { - gamepath_btns[i].disabled = false; - gamepath_btns[i].classList.remove("disabled"); - } - } -} - -// `percent` should be a number between 0 to 100, if it's `false` it'll -// reset it back to nothing instantly, with no animatino -function set_ns_progress(percent) { - // reset button progress - if (percent === false) { - document.querySelector(".contentContainer #nsMain .playBtn") - .style.setProperty("--progress", "unset"); - - return; - } - - percent = parseInt(percent); - - // make sure we're dealing with a number - if (isNaN(percent) || typeof percent !== "number") { - return false; - } - - // limit percent, while this barely has a difference, if you were to - // set a very high number, the CSS would then use a very high - // number, not great. - if (percent > 100) { - percent = 100; - } else if (percent < 0) { - percent = 0; - } - - // invert number to it works in the CSS - percent = 100 - percent; - - // set the CSS progress variable - document.querySelector(".contentContainer #nsMain .playBtn") - .style.setProperty("--progress", percent + "%"); -} - -ipcRenderer.on("set-buttons", (event, state) => { - setButtons(state); -}) - -ipcRenderer.on("gamepath-lost", (event, state) => { - page(0); - setButtons(false, true); - alert(lang("gui.gamepath.lost")); -}) - -// Frontend part of updating Northstar -ipcRenderer.on("ns-update-event", (event, options) => { - let key = options.key; - if (typeof options == "string") { - key = options; - } - - // updates text in update button to `lang(key)` - let update_btn = () => { - document.getElementById("update") - .innerText = `(${lang(key)})`; - } - - switch(key) { - case "cli.update.uptodate_short": - case "cli.update.no_internet": - // initial value - let delay = 0; - - // get current time - let now = new Date().getTime(); - - // check if `checked_for_ns_update` was less than 500ms - // since now, this variable is set when `updateNorthstar()` - // is called - if (now - checked_for_ns_update < 500) { - // if less than 500ms has passed, set `delay` to the - // amount of milliseconds missing until we've hit that - // 500ms threshold - delay = 500 - (now - checked_for_ns_update); - } - - // wait `delay`ms - setTimeout(() => { - // set buttons accordingly - update_btn(); - setButtons(true); - set_ns_progress(false); - playNsBtn.innerText = lang("gui.launch"); - }, delay) - - break; - default: - update_btn(); - - if (options.progress) { - set_ns_progress(options.progress); - } - - if (options.btn_text) { - playNsBtn.innerText = options.btn_text; - } - - setButtons(false); - break; - } -}); ipcRenderer.on("unknown-error", (event, err) => { new Toast({ @@ -331,238 +21,21 @@ ipcRenderer.on("unknown-error", (event, err) => { } }) - console.error(err.stack) -}) - -let installqueue = []; - -// Tells the main process to install a mod through the file selector -function installmod() { - setButtons(false); - ipcRenderer.send("install-mod"); -} - -// Tells the main process to directly install a mod from this path -function installFromPath(path) { - setButtons(false); - ipcRenderer.send("install-from-path", path); -} - -// Tells the main process to install a mod from a URL -function installFromURL(url, dependencies, clearqueue, author, package_name, version) { - if (clearqueue) {installqueue = []}; - - let prettydepends = []; - - if (dependencies) { - let newdepends = []; - for (let i = 0; i < dependencies.length; i++) { - let depend = dependencies[i].toLowerCase(); - if (! depend.match(/northstar-northstar-.*/)) { - depend = dependencies[i].replaceAll("-", "/"); - let pkg = depend.split("/"); - if (! isModInstalled(pkg[1])) { - newdepends.push({ - pkg: depend, - author: pkg[0], - version: pkg[2], - package_name: pkg[1] - }); - - prettydepends.push(`${pkg[1]} v${pkg[2]} - ${lang("gui.browser.made_by")} ${pkg[0]}`); - } - } - } - - dependencies = newdepends; - } - - if (dependencies && dependencies.length != 0) { - let confirminstall = confirm(lang("gui.mods.confirm_dependencies") + prettydepends.join("\n")); - if (! confirminstall) { - return - } - } - - setButtons(false); - ipcRenderer.send("install-from-url", url, author, package_name, version); - - if (dependencies) { - installqueue = dependencies; - } -} - -function isModInstalled(modname) { - for (let i = 0; i < modsobj.all.length; i++) { - let mod = modsobj.all[i]; - if (mod.manifest_name) { - if (mod.manifest_name.match(modname)) { - return true; - } - } else if (mod.name.match(modname)) { - return true; - } - } - - return false; -} - -// Frontend part of settings a new game path -ipcRenderer.on("newpath", (event, newpath) => { - setButtons(true); - settings.gamepath = newpath; - ipcRenderer.send("gui-getmods"); - ipcRenderer.send("save-settings", settings); -}) - -// Continuation of log() -ipcRenderer.on("log", (event, msg) => {log(msg)}) -ipcRenderer.on("alert", (event, data) => { - alert(data.message); - ipcRenderer.send("alert-closed-" + data.id); + console.error(err.stack); }) -ipcRenderer.on("confirm", (event, data) => { - let confirmed = confirm(data.message); - ipcRenderer.send("confirm-closed-" + data.id, confirmed); -}) - -let is_running = false; -ipcRenderer.on("is-running", (event, running) => { - let set_playbtns = (text) => { - let playbtns = document.querySelectorAll(".playBtn"); - for (let i = 0; i < playbtns.length; i++) { - playbtns[i].innerHTML = text; - } - } - - if (running && is_running != running) { - setButtons(false); - set_playbtns(lang("general.running")); - - is_running = running; - - // show force quit button in Titanfall tab - tfquit.style.display = "inline-block"; - - update.setAttribute("onclick", "kill_game()"); - update.innerHTML = "(" + lang("ns.menu.force_quit") + ")"; - return; - } - - if (is_running != running) { - setButtons(true); - set_playbtns(lang("gui.launch")); - - is_running = running; - - // hide force quit button in Titanfall tab - tfquit.style.display = "none"; - - update.setAttribute("onclick", "updateNorthstar()"); - update.innerHTML = "(" + lang("gui.update.check") + ")"; - } -}) - -function kill_game() { - ipcRenderer.send("kill-game"); -} - -function kill_origin() { - ipcRenderer.send("kill-origin"); -} - -function delete_request_cache() { - ipcRenderer.send("delete-request-cache"); -} - -function delete_install_cache() { - ipcRenderer.send("delete-install-cache"); -} - -// Updates the installed mods -ipcRenderer.on("mods", (event, mods_obj) => { - modsobj = mods_obj; - if (! mods_obj) {return} - - mods.load(mods_obj); -}) - -// Updates version numbers -ipcRenderer.on("version", (event, versions) => { - vpversion.innerText = versions.vp; - nsversion.innerText = versions.ns; - tf2Version.innerText = versions.tf2; - - if (versions.ns == "unknown") { - let buttons = document.querySelectorAll(".modbtns button"); - - for (let i = 0; i < buttons.length; i++) { - buttons[i].disabled = true; - } - - // Since Northstar is not installed, we cannot launch it - shouldInstallNorthstar = true; - playNsBtn.innerText = lang("gui.install"); - } -}); ipcRenderer.send("get-version"); - -// When an update is available it'll ask the user about it -ipcRenderer.on("update-available", () => { - if (confirm(lang("gui.update.available"))) { - ipcRenderer.send("update-now"); - } -}) - -// Error out when no game path is set -ipcRenderer.on("no-path-selected", () => { - alert(lang("gui.gamepath.must")); - exit(); -}); - -// Error out when game path is wrong -ipcRenderer.on("wrong-path", () => { - alert(lang("gui.gamepath.wrong")); - setpath(false); -}); - -setlang(); - -let dragtimer; -document.addEventListener("dragover", (e) => { - e.preventDefault(); - e.stopPropagation(); - dragUI.classList.add("shown"); - - clearTimeout(dragtimer); - dragtimer = setTimeout(() => { - dragUI.classList.remove("shown"); - }, 5000) -}); - -document.addEventListener("mouseover", (e) => { - clearTimeout(dragtimer); - dragUI.classList.remove("shown"); -}); - -document.addEventListener("drop", (e) => { - event.preventDefault(); - event.stopPropagation(); - - dragUI.classList.remove("shown"); - installFromPath(event.dataTransfer.files[0].path); -}); - -document.body.addEventListener("keyup", (e) => { - if (e.key == "Escape") { - Browser.toggle(false); - Settings.toggle(false); - } -}) +const json = require("../modules/json"); -document.body.addEventListener("click", event => { - if (event.target.tagName.toLowerCase() === "a" && event.target.protocol != "file:") { - event.preventDefault(); - shell.openExternal(event.target.href); - } -}); +const kill = require("./js/kill"); +const update = require("./js/update"); +const events = require("./js/events"); +const launch = require("./js/launch"); +const request = require("./js/request"); +const process = require("./js/process"); +const settings = require("./js/settings"); +const gamepath = require("./js/gamepath"); +const is_running = require("./js/is_running"); +const set_buttons = require("./js/set_buttons"); + +require("./js/dom_events"); +require("./js/set_dom_strings")(); diff --git a/src/modules/kill.js b/src/modules/kill.js index 5d03218..b0c4f97 100644 --- a/src/modules/kill.js +++ b/src/modules/kill.js @@ -1,12 +1,10 @@ const exec = require("child_process").exec; const ipcMain = require("electron").ipcMain; -ipcMain.on("kill-game", () => { - kill.game(); -}) - -ipcMain.on("kill-origin", () => { - kill.origin(); +ipcMain.on("kill", (function_name) => { + if (typeof kill[function_name] == "function") { + kill[function_name](); + } }) // a simple function to kill processes with a certain name -- cgit v1.2.3 From 7f011d34a2d5e13ba312b44ce6871e48a495ea8f Mon Sep 17 00:00:00 2001 From: 0neGal Date: Sat, 8 Jun 2024 18:10:06 +0200 Subject: replace js/misc.js file with js/version.js module --- src/app/index.html | 1 - src/app/js/misc.js | 44 -------------------------------------------- src/app/js/version.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/app/main.js | 1 + 4 files changed, 45 insertions(+), 45 deletions(-) delete mode 100644 src/app/js/misc.js create mode 100644 src/app/js/version.js diff --git a/src/app/index.html b/src/app/index.html index 87a1029..1297d0a 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -333,7 +333,6 @@ - diff --git a/src/app/js/misc.js b/src/app/js/misc.js deleted file mode 100644 index b35f239..0000000 --- a/src/app/js/misc.js +++ /dev/null @@ -1,44 +0,0 @@ -version = { - is_newer: (version1, version2) => { - version1 = version.format(version1, true).split("."); - version2 = version.format(version2, true).split("."); - - for (let i = 0; i < version1.length; i++) { - - - let nums = [ - parseInt(version1[i]) || 0, - parseInt(version2[i]) || 0 - ]; - if (nums[0] > nums[1]) { - return true; - } else if (nums[0] < nums[1]) { - return false; - } - } - - return false; - }, - format: (version_number, no_leading_v) => { - version_number = version_number.trim(); - - if (no_leading_v) { - if (version_number[0] == "v") { - return version_number.slice(1, version_number.length); - } - - return version_number; - if (no_leading_v) { - return version_number - } - - return "v" + version_number; - } else { - if (version_number[0] != "v") { - return "v" + version_number; - } - } - - return version_number; - } -} diff --git a/src/app/js/version.js b/src/app/js/version.js new file mode 100644 index 0000000..97223f9 --- /dev/null +++ b/src/app/js/version.js @@ -0,0 +1,44 @@ +module.exports = { + is_newer: (version1, version2) => { + version1 = version.format(version1, true).split("."); + version2 = version.format(version2, true).split("."); + + for (let i = 0; i < version1.length; i++) { + + + let nums = [ + parseInt(version1[i]) || 0, + parseInt(version2[i]) || 0 + ]; + if (nums[0] > nums[1]) { + return true; + } else if (nums[0] < nums[1]) { + return false; + } + } + + return false; + }, + format: (version_number, no_leading_v) => { + version_number = version_number.trim(); + + if (no_leading_v) { + if (version_number[0] == "v") { + return version_number.slice(1, version_number.length); + } + + return version_number; + if (no_leading_v) { + return version_number + } + + return "v" + version_number; + } else { + if (version_number[0] != "v") { + return "v" + version_number; + } + } + + return version_number; + } +} diff --git a/src/app/main.js b/src/app/main.js index 2ed3053..11f5853 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -30,6 +30,7 @@ const kill = require("./js/kill"); const update = require("./js/update"); const events = require("./js/events"); const launch = require("./js/launch"); +const version = require("./js/version"); const request = require("./js/request"); const process = require("./js/process"); const settings = require("./js/settings"); -- cgit v1.2.3 From a8e0f5f0435ed6cedb4ff389ee31c210dab26100 Mon Sep 17 00:00:00 2001 From: 0neGal Date: Sat, 8 Jun 2024 18:12:13 +0200 Subject: convert js/mods.js to a CommonJS module --- src/app/index.html | 1 - src/app/js/mods.js | 13 +++++++++++-- src/app/main.js | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/app/index.html b/src/app/index.html index 1297d0a..4b89999 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -333,7 +333,6 @@ - diff --git a/src/app/js/mods.js b/src/app/js/mods.js index e105c7c..caa66a7 100644 --- a/src/app/js/mods.js +++ b/src/app/js/mods.js @@ -1,3 +1,10 @@ +const ipcRenderer = require("electron").ipcRenderer; + +const lang = require("../../lang"); + +const version = require("./version"); +const set_buttons = require("./set_buttons"); + let mods = {}; let mods_list = { @@ -15,7 +22,7 @@ mods.load = (mods_obj) => { modcount.innerHTML = `${lang("gui.mods.count")} ${mods_obj.all.length}`; let normalized_names = []; - + let set_mod = (mod) => { let name = mod.name; if (mod.package) { @@ -185,7 +192,7 @@ mods.load = (mods_obj) => { mods.toggle(mod_versions[mod].local_name); } }) - + mod_els[i].remove(); modsdiv.querySelector(".line").after(mod_el); } else { @@ -303,3 +310,5 @@ ipcRenderer.on("mods", (event, mods_obj) => { mods.load(mods_obj); }) + +module.exports = mods; diff --git a/src/app/main.js b/src/app/main.js index 11f5853..fa4ec86 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -27,6 +27,7 @@ ipcRenderer.on("unknown-error", (event, err) => { const json = require("../modules/json"); const kill = require("./js/kill"); +const mods = require("./js/mods"); const update = require("./js/update"); const events = require("./js/events"); const launch = require("./js/launch"); -- cgit v1.2.3 From 05b13e99a2ec632c63557c52ec22677b022e7d69 Mon Sep 17 00:00:00 2001 From: 0neGal Date: Sat, 8 Jun 2024 18:20:53 +0200 Subject: convert js/toast.js to a CommonJS module Renamed from `toast.js` to `toasts.js` as well --- src/app/index.html | 1 - src/app/js/browser.js | 10 +++---- src/app/js/toast.js | 71 ----------------------------------------------- src/app/js/toasts.js | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/app/main.js | 5 ++-- 5 files changed, 85 insertions(+), 79 deletions(-) delete mode 100644 src/app/js/toast.js create mode 100644 src/app/js/toasts.js diff --git a/src/app/index.html b/src/app/index.html index 4b89999..5d5f0fc 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -333,7 +333,6 @@ - diff --git a/src/app/js/browser.js b/src/app/js/browser.js index 00a0933..9a1298a 100644 --- a/src/app/js/browser.js +++ b/src/app/js/browser.js @@ -480,7 +480,7 @@ ipcRenderer.on("failed-mod", (event, modname) => { add_recent_toast("failed" + modname); set_buttons(true); - new Toast({ + toasts.show({ timeout: 10000, scheme: "error", title: lang("gui.toast.title.failed"), @@ -493,7 +493,7 @@ ipcRenderer.on("legacy-duped-mod", (event, modname) => { add_recent_toast("duped" + modname); set_buttons(true); - new Toast({ + toasts.show({ timeout: 10000, scheme: "warning", title: lang("gui.toast.title.duped"), @@ -503,7 +503,7 @@ ipcRenderer.on("legacy-duped-mod", (event, modname) => { ipcRenderer.on("no-internet", (event, modname) => { set_buttons(true); - new Toast({ + toasts.show({ timeout: 10000, scheme: "error", title: lang("gui.toast.title.no_internet"), @@ -521,7 +521,7 @@ ipcRenderer.on("installed-mod", (event, mod) => { Browser.setbutton(name, lang("gui.browser.reinstall"), "redo"); if (mod.malformed) { - new Toast({ + toasts.show({ timeout: 8000, scheme: "warning", title: lang("gui.toast.title.malformed"), @@ -529,7 +529,7 @@ ipcRenderer.on("installed-mod", (event, mod) => { }) } - new Toast({ + toasts.show({ scheme: "success", title: lang("gui.toast.title.installed"), description: name + " " + lang("gui.toast.desc.installed") diff --git a/src/app/js/toast.js b/src/app/js/toast.js deleted file mode 100644 index e0aba6b..0000000 --- a/src/app/js/toast.js +++ /dev/null @@ -1,71 +0,0 @@ -function Toast(properties) { - let toast = { - timeout: 3000, - fg: "#FFFFFF", - bg: "var(--selbg)", - callback: () => {}, - title: "Untitled Toast", - description: "No description provided for toast", - ...properties - } - - switch(toast.scheme) { - case "error": - toast.fg = "#FFFFFF"; - toast.bg = "rgb(var(--red))"; - break - case "success": - toast.fg = "#FFFFFF"; - toast.bg = "#60D394"; - break - case "warning": - toast.fg = "#FFFFFF"; - toast.bg = "#FF9B85"; - break - } - - - let id = Date.now(); - if (document.getElementById(id)) {id = id + 1} - let el = document.createElement("div"); - - el.classList.add("toast"); - - el.style.color = toast.fg; - el.style.background = toast.bg; - - el.id = id; - el.addEventListener("click", () => { - dismissToast(id); - toast.callback(); - }) - - el.innerHTML = ` -
${toast.title}
-
${toast.description}
- ` - - if (! toast.title) { - el.querySelector(".title").remove(); - } - - if (! toast.description) { - el.querySelector(".description").remove(); - } - - toasts.appendChild(el); - - setTimeout(() => { - dismissToast(id); - }, toast.timeout) -} - -function dismissToast(id) { - id = document.getElementById(id); - if (id) { - id.classList.add("hidden"); - setTimeout(() => { - id.remove(); - }, 500) - } -} diff --git a/src/app/js/toasts.js b/src/app/js/toasts.js new file mode 100644 index 0000000..c3bba99 --- /dev/null +++ b/src/app/js/toasts.js @@ -0,0 +1,77 @@ +let toasts = {}; + +toasts.show = (properties) => { + let toast = { + timeout: 3000, + fg: "#FFFFFF", + bg: "var(--selbg)", + callback: () => {}, + title: "Untitled Toast", + description: "No description provided for toast", + ...properties + } + + switch(toast.scheme) { + case "error": + toast.fg = "#FFFFFF"; + toast.bg = "rgb(var(--red))"; + break + case "success": + toast.fg = "#FFFFFF"; + toast.bg = "#60D394"; + break + case "warning": + toast.fg = "#FFFFFF"; + toast.bg = "#FF9B85"; + break + } + + + let id = Date.now(); + if (document.getElementById(id)) {id = id + 1} + let el = document.createElement("div"); + + el.classList.add("toast"); + + el.style.color = toast.fg; + el.style.background = toast.bg; + + el.id = id; + el.addEventListener("click", () => { + toasts.dismiss(id); + toast.callback(); + }) + + el.innerHTML = ` +
${toast.title}
+
${toast.description}
+ ` + + if (! toast.title) { + el.querySelector(".title").remove(); + } + + if (! toast.description) { + el.querySelector(".description").remove(); + } + + document.getElementById("toasts").appendChild(el); + + setTimeout(() => { + toasts.dismiss(id); + }, toast.timeout) +} + +// dismissed/closes toasts with `id` as their ID +toasts.dismiss = (id) => { + id = document.getElementById(id); + + if (id) { + id.classList.add("hidden"); + setTimeout(() => { + id.remove(); + }, 500) + } +} + +module.exports = toasts; diff --git a/src/app/main.js b/src/app/main.js index fa4ec86..9ad6344 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -6,13 +6,13 @@ const { app, ipcRenderer, shell } = require("electron"); const lang = require("../lang"); ipcRenderer.on("unknown-error", (event, err) => { - new Toast({ + toasts.show({ timeout: 10000, scheme: "error", title: lang("gui.toast.title.unknown_error"), description: lang("gui.toast.desc.unknown_error"), callback: () => { - new Toast({ + toasts.show({ timeout: 15000, scheme: "error", title: "", @@ -28,6 +28,7 @@ const json = require("../modules/json"); const kill = require("./js/kill"); const mods = require("./js/mods"); +const toasts = require("./js/toasts"); const update = require("./js/update"); const events = require("./js/events"); const launch = require("./js/launch"); -- cgit v1.2.3 From ceb90ab941a159d63ea5cace1c24dde6b8b96a86 Mon Sep 17 00:00:00 2001 From: 0neGal Date: Sat, 8 Jun 2024 18:26:13 +0200 Subject: move browser.js' normalize() into mods.js --- src/app/js/browser.js | 34 ++++++++-------------------------- src/app/js/mods.js | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/app/js/browser.js b/src/app/js/browser.js index 9a1298a..ec5a31d 100644 --- a/src/app/js/browser.js +++ b/src/app/js/browser.js @@ -111,7 +111,7 @@ var Browser = { add_pkg_properties: () => { for (let i = 0; i < packages.length; i++) { let properties = packages[i]; - let normalized = normalize(packages[i].name); + let normalized = mods.normalize(packages[i].name); let has_update = false; let local_name = false; @@ -123,7 +123,7 @@ var Browser = { for (let ii = 0; ii < mods.list().all.length; ii++) { let mod = mods.list().all[ii]; - if (normalize(mod.name) !== normalized && ( + if (mods.normalize(mod.name) !== normalized && ( ! mod.package || mod.package.author + "-" + mod.package.package_name !== packages[i].full_name @@ -266,7 +266,7 @@ var Browser = { } }, setbutton: (mod, string, icon) => { - mod = normalize(mod); + mod = mods.normalize(mod); if (browserEntries.querySelector(`#mod-${mod}`)) { let elems = browserEntries.querySelectorAll(`.el#mod-${mod}`); @@ -289,13 +289,13 @@ var Browser = { setTimeout(() => { for (let i = 0; i < mods.list().all.length; i++) { - let modname = normalize(mods.list().all[i].name); - let modfolder = normalize(mods.list().all[i].folder_name); + let modname = mods.normalize(mods.list().all[i].name); + let modfolder = mods.normalize(mods.list().all[i].folder_name); if (mod.includes(modname)) { if (! make(modname)) { if (mods.list().all[i].manifest_name) { - make(normalize(mods.list().all[i].manifest_name)); + make(mods.normalize(mods.list().all[i].manifest_name)); } } } @@ -406,7 +406,7 @@ function BrowserEl(properties) { let normalized_mods = []; for (let i = 0; i < mods.list().all; i++) { - normalized_mods.push(normalize(mods_list[i].name)); + normalized_mods.push(mods.normalize(mods_list[i].name)); } if (properties.pkg.local_version) { @@ -421,7 +421,7 @@ function BrowserEl(properties) { let entry = document.createElement("div"); entry.classList.add("el"); - entry.id = `mod-${normalize(properties.title)}`; + entry.id = `mod-${mods.normalize(properties.title)}`; entry.innerHTML = `
@@ -545,24 +545,6 @@ ipcRenderer.on("installed-mod", (event, mod) => { } }) -function normalize(items) { - let main = (string) => { - return string.replaceAll(" ", "") - .replaceAll(".", "").replaceAll("-", "") - .replaceAll("_", "").toLowerCase(); - } - if (typeof items == "string") { - return main(items); - } else { - let newArray = []; - for (let i = 0; i < items.length; i++) { - newArray.push(main(items[i])); - } - - return newArray; - } -} - let searchtimeout; let searchstr = ""; let search = document.querySelector("#browser .search"); diff --git a/src/app/js/mods.js b/src/app/js/mods.js index caa66a7..7110d7e 100644 --- a/src/app/js/mods.js +++ b/src/app/js/mods.js @@ -29,7 +29,7 @@ mods.load = (mods_obj) => { name = mod.package.package_name; } - let normalized_name = "mod-list-" + normalize(name); + let normalized_name = "mod-list-" + mods.normalize(name); normalized_names.push(normalized_name); @@ -302,6 +302,23 @@ mods.is_installed = (modname) => { return false; } +mods.normalize = (items) => { + let main = (string) => { + return string.replaceAll(" ", "") + .replaceAll(".", "").replaceAll("-", "") + .replaceAll("_", "").toLowerCase(); + } + if (typeof items == "string") { + return main(items); + } else { + let newArray = []; + for (let i = 0; i < items.length; i++) { + newArray.push(main(items[i])); + } + + return newArray; + } +} // updates the installed mods ipcRenderer.on("mods", (event, mods_obj) => { -- cgit v1.2.3 From 0577977182e7f4be2722f54ae50ff23aa8fe9032 Mon Sep 17 00:00:00 2001 From: 0neGal Date: Sat, 8 Jun 2024 18:36:27 +0200 Subject: convert js/launcher.js to a CommonJS module --- src/app/index.html | 19 +++++++++---------- src/app/js/gamepath.js | 3 ++- src/app/js/launcher.js | 40 ++++++++++++++++++++++------------------ src/app/main.js | 1 + 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/app/index.html b/src/app/index.html index 5d5f0fc..d6df23e 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -230,17 +230,17 @@
    -
  • %%viper.menu.main%%
  • -
  • %%viper.menu.release%%
  • -
  • %%viper.menu.info%%
  • +
  • %%viper.menu.main%%
  • +
  • %%viper.menu.release%%
  • +
  • %%viper.menu.info%%
@@ -269,9 +269,9 @@
    -
  • %%ns.menu.main%%
  • -
  • %%ns.menu.mods%%
  • -
  • %%ns.menu.release%%
  • +
  • %%ns.menu.main%%
  • +
  • %%ns.menu.mods%%
  • +
  • %%ns.menu.release%%
@@ -336,6 +336,5 @@ - diff --git a/src/app/js/gamepath.js b/src/app/js/gamepath.js index 80e3158..c3e5c2b 100644 --- a/src/app/js/gamepath.js +++ b/src/app/js/gamepath.js @@ -2,6 +2,7 @@ const ipcRenderer = require("electron").ipcRenderer; const lang = require("../../lang"); const process = require("./process"); +const launcher = require("./launcher"); const settings = require("./settings"); // frontend part of settings a new game path @@ -16,7 +17,7 @@ ipcRenderer.on("newpath", (_, newpath) => { // a previously valid gamepath no longer exists, and is therefore lost ipcRenderer.on("gamepath-lost", () => { - page(0); + launcher.change_page(0); set_buttons(false, true); alert(lang("gui.gamepath.lost")); }) diff --git a/src/app/js/launcher.js b/src/app/js/launcher.js index 6fe1686..913762b 100644 --- a/src/app/js/launcher.js +++ b/src/app/js/launcher.js @@ -1,11 +1,13 @@ const markdown = require("marked").parse; +let launcher = {}; + var servercount; var playercount; var masterserver; // changes the main page, this is the tabs in the sidebar -function page(page) { +launcher.change_page = (page) => { let btns = document.querySelectorAll(".gamesContainer button"); let pages = document.querySelectorAll(".mainContainer .contentContainer"); @@ -20,9 +22,9 @@ function page(page) { pages[page].classList.remove("hidden"); btns[page].classList.remove("inactive"); bgHolder.setAttribute("bg", page); -}; page(1) +}; launcher.change_page(1) -function formatRelease(notes) { +launcher.format_release = (notes) => { if (! notes) {return ""} let content = ""; @@ -61,7 +63,7 @@ function formatRelease(notes) { // sets content of `div` to a single release block with centered text // inside it, the text being `lang(lang_key)` -let set_error_content = (div, lang_key) => { +launcher.error = (div, lang_key) => { div.innerHTML = "
" + "

" + @@ -73,39 +75,39 @@ let set_error_content = (div, lang_key) => { // updates the Viper release notes ipcRenderer.on("vp-notes", (event, response) => { if (! response) { - return set_error_content( + return launcher.error( vpReleaseNotes, "request.no_vp_release_notes" ) } - vpReleaseNotes.innerHTML = formatRelease(response); + vpReleaseNotes.innerHTML = launcher.format_release(response); }); // updates the Northstar release notes ipcRenderer.on("ns-notes", (event, response) => { if (! response) { - return set_error_content( + return launcher.error( nsRelease, "request.no_ns_release_notes" ) } - nsRelease.innerHTML = formatRelease(response); + nsRelease.innerHTML = launcher.format_release(response); }); -async function loadVpReleases() { +launcher.load_vp_notes = async () => { ipcRenderer.send("get-vp-notes"); -}; loadVpReleases(); +}; launcher.load_vp_notes(); -async function loadNsReleases() { +launcher.load_ns_notes = async () => { ipcRenderer.send("get-ns-notes"); -}; loadNsReleases(); +}; launcher.load_ns_notes(); // TODO: We gotta make this more automatic instead of switch statements // it's both not pretty, but adding more sections requires way too much // effort, compared to how it should be. -function showVpSection(section) { +launcher.show_vp = (section) => { if (!["main", "release", "info", "credits"].includes(section)) throw new Error("unknown vp section"); vpMainBtn.removeAttribute("active"); vpReleaseBtn.removeAttribute("active"); @@ -131,8 +133,8 @@ function showVpSection(section) { } } -function showNsSection(section) { - if (!["main", "release", "mods"].includes(section)) { +launcher.show_ns = (section) => { + if (! ["main", "release", "mods"].includes(section)) { throw new Error("unknown ns section"); } @@ -161,7 +163,7 @@ function showNsSection(section) { } } -async function loadServers() { +launcher.check_servers = async () => { serverstatus.classList.add("checking"); try { @@ -205,9 +207,11 @@ async function loadServers() { serverstatus.innerHTML = lang("gui.server.offline"); } -}; loadServers() +}; launcher.check_servers() // refreshes every 5 minutes setInterval(() => { - loadServers(); + launcher.check_servers(); }, 300000) + +module.exports = launcher; diff --git a/src/app/main.js b/src/app/main.js index 9ad6344..b72c1f9 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -37,6 +37,7 @@ const request = require("./js/request"); const process = require("./js/process"); const settings = require("./js/settings"); const gamepath = require("./js/gamepath"); +const launcher = require("./js/launcher"); const is_running = require("./js/is_running"); const set_buttons = require("./js/set_buttons"); -- cgit v1.2.3 From d4d95da09a04cc8b07fbcf6e179f4edb5e662b98 Mon Sep 17 00:00:00 2001 From: 0neGal Date: Sat, 8 Jun 2024 18:38:11 +0200 Subject: convert js/tooltip.js to a CommonJS module It's not actually used anywhere outside of itself, but oh well. --- src/app/index.html | 1 - src/app/js/tooltip.js | 2 ++ src/app/main.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/index.html b/src/app/index.html index d6df23e..a591a26 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -334,7 +334,6 @@ - diff --git a/src/app/js/tooltip.js b/src/app/js/tooltip.js index 13dcd67..f2d97a0 100644 --- a/src/app/js/tooltip.js +++ b/src/app/js/tooltip.js @@ -128,3 +128,5 @@ document.addEventListener("mousedown", tooltip_event); document.addEventListener("mousemove", tooltip_event); document.addEventListener("mouseenter", tooltip_event); document.addEventListener("mouseleave", tooltip_event); + +module.exports = tooltip; diff --git a/src/app/main.js b/src/app/main.js index b72c1f9..04055a8 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -32,6 +32,7 @@ const toasts = require("./js/toasts"); const update = require("./js/update"); const events = require("./js/events"); const launch = require("./js/launch"); +const tooltip = require("./js/tooltip"); const version = require("./js/version"); const request = require("./js/request"); const process = require("./js/process"); -- cgit v1.2.3 From 957f2d2ff52c9917960c4c8d55eab3b44f0453bb Mon Sep 17 00:00:00 2001 From: 0neGal Date: Sat, 8 Jun 2024 20:17:48 +0200 Subject: convert js/browser.js to a CommonJS module And `js/popups.js`, but it was already technically a CommonJS module, it was just leftover in `index.html` due to `js/browser.js` not being a CommonJS module. --- src/app/index.html | 10 ++-- src/app/js/browser.js | 143 ++++++++++++++++++++++++++--------------------- src/app/js/dom_events.js | 2 +- src/app/js/mods.js | 14 ++--- src/app/main.js | 2 + 5 files changed, 92 insertions(+), 79 deletions(-) diff --git a/src/app/index.html b/src/app/index.html index a591a26..ffc13de 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -205,10 +205,10 @@
- -
@@ -218,7 +218,7 @@