const util = require('util');
const ipcRenderer = require("electron").ipcRenderer;
const lang = require("../../lang");
const version = require("./version");
const toasts = require("./toasts");
const set_buttons = require("./set_buttons");
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}`;
let normalized_names = [];
let set_mod = (mod) => {
let name = mod.name;
if (mod.package) {
name = mod.package.package_name;
}
let normalized_name = "mod-list-" + mods.normalize(name);
normalized_names.push(normalized_name);
let el = document.getElementById(normalized_name);
if (el) {
if (mod.disabled) {
el.querySelector(".switch").classList.remove("on");
} else {
el.querySelector(".switch").classList.add("on");
}
return;
}
let div = document.createElement("div");
div.classList.add("el");
div.id = normalized_name;
let mod_details = {
name: mod.name,
version: mod.version,
description: mod.description
}
if (mod.package) {
mod_details = {
image: mod.package.icon,
name: mod.package.manifest.name,
version: mod.package.manifest.version_number,
description: mod.package.manifest.description
}
}
div.innerHTML += `
${mod_details.name}
${mod_details.description}
`;
if (mod_details.name.match(/^Northstar\..*/)) {
div.querySelector("img").src = "icons/northstar.png"
}
div.querySelector(".remove").onclick = () => {
if (! mod.package) {
return mods.remove(mod.name);
}
for (let i = 0; i < mod.packaged_mods.length; i++) {
mods.remove(mod.packaged_mods[i]);
}
}
if (mod.disabled) {
div.querySelector(".switch").classList.remove("on");
}
div.querySelector(".switch").addEventListener("click", () => {
if (! mod.package) {
return mods.toggle(mod.name);
}
for (let i = 0; i < mod.packaged_mods.length; i++) {
mods.toggle(mod.packaged_mods[i]);
}
})
div.querySelector(".image").style.display = "none";
modsdiv.append(div);
}
for (let i = 0; i < mods_obj.all.length; i++) {
set_mod(mods_obj.all[i]);
}
let mod_els = document.querySelectorAll("#modsdiv .el");
let mod_update_els = [];
for (let i = 0; i < mod_els.length; i++) {
let update_btn = mod_els[i].querySelector(".update");
if (update_btn && update_btn.style.display != "none") {
mod_update_els.push(mod_els[i].id);
} else {
break;
}
}
for (let i = 0; i < mod_els.length; i++) {
let mod = mod_els[i].id.replace(/^mod-list-/, "");
if (! normalized_names.includes(mod_els[i].id)) {
mod_els[i].remove();
return;
}
let image_container = mod_els[i].querySelector(".image");
let image_el = image_container.querySelector("img")
let image_blur_el = image_container.querySelector("img.blur")
if (browser.mod_versions[mod]) {
image_el.src = browser.mod_versions[mod].package.versions[0].icon;
}
if (image_el.getAttribute("src") &&
! image_container.parentElement.classList.contains("has-icon")) {
let image_src = image_el.getAttribute("src");
image_blur_el.src = image_src;
image_container.style.display = null;
image_container.parentElement.classList.add("has-icon");
}
if (browser.mod_versions[mod]
&& browser.mod_versions[mod].has_update) {
mod_els[i].querySelector(".update").style.display = null;
mod_els[i].querySelector(".update").setAttribute(
"onclick", `browser.mod_versions["${mod}"].install()`
)
if (mod_update_els.includes(mod_els[i].id)) {
continue;
}
let mod_el = mod_els[i].cloneNode(true);
// copy click event of the remove button to the new button
mod_el.querySelector(".remove").onclick =
mod_els[i].querySelector(".remove").onclick;
mod_el.classList.add("no-animation");
mod_el.querySelector(".switch").addEventListener("click", () => {
if (browser.mod_versions[mod].local_name) {
mods.toggle(browser.mod_versions[mod].local_name);
}
})
mod_els[i].remove();
modsdiv.querySelector(".line").after(mod_el);
} else {
mod_els[i].querySelector(".update").style.display = "none";
}
}
}
// attempts to filter `#modsdiv` with `query`
mods.search = (query) => {
// if no `query` is given, use the search input's value
if (! query) {
query = mods.search.el.value;
}
// normalizes `string`
let normalize = (string) => {
return string
.trim().toLowerCase()
.replaceAll(" ", "").replaceAll(".", "");
}
// normalize `query`
query = normalize(query);
// get all mod elements
let mod_els = document.querySelectorAll("#modsdiv .el");
// run through all the mod elements
for (let mod_el of mod_els) {
// get the normalized name of the mod
let name = normalize(mod_el.querySelector(".title").innerText);
// if the name has `query` in it, show it
if (name.match(query)) {
mod_el.style.display = null;
} else { // hide if it doesn't match
mod_el.style.display = "none";
}
}
}
mods.search.el = document.getElementById("mods-search");
mods.search.el.addEventListener("keyup", () => {mods.search()})
mods.remove = (mod) => {
if (mod.toLowerCase().match(/^northstar\./)) {
if (! confirm(lang("gui.mods.required_confirm"))) {
return;
}
} else if (mod == "allmods") {
if (! confirm(lang("gui.mods.remove_all_confirm"))) {
return;
}
}
ipcRenderer.send("remove-mod", mod);
}
mods.toggle = (mod) => {
// is this a core mod?
if (mod.toLowerCase().match(/^northstar\./)) {
// keep track of whether this mod is disabled
let is_disabled = false;
// run through disabled mods
for (let mod_obj of mods_list.disabled) {
// if `mod` is `mod_obj`, update `is_disabled`
if (mod_obj.name.toLowerCase() == mod.toLowerCase()) {
is_disabled = true;
break;
}
}
// show prompt if the mod is enabled
if (! is_disabled && ! confirm(lang("gui.mods.required_confirm"))) {
return;
}
} else if (mod == "allmods") {
if (! confirm(lang("gui.mods.toggle_all_confirm"))) {
return;
}
}
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;
}
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) => {
mods_list = mods_obj;
if (! mods_obj) {return}
mods.load(mods_obj);
})
ipcRenderer.on("protocol-install-mod", async (event, data) => {
const domain = data[0];
const author = data[1];
const package_name = data[2];
const version = data[3];
const packages = await browser.packages();
const package = packages.find((package) => { return package.owner == author && package.name == package_name; })
if (!package) {
alert(util.format(lang("gui.mods.cant_find_specific"), author, package_name));
return;
}
const package_obj = package.versions.find((package_version) => { return package_version.version_number == version; })
if (!package_obj) {
alert(util.format(lang("gui.mods.cant_find_version"), version, author, package_name))
return;
}
toasts.show({
timeout: 3000,
scheme: "info",
title: lang("gui.mods.installing"),
description: package_obj.full_name
})
mods.install_from_url(
package_obj.download_url,
package_obj.dependencies,
false,
author,
package_name,
version
);
})
module.exports = mods;