const Fuse = require("fuse.js");
var fuse;
var packages = [];
var packagecount = 0;
var Browser = {
maxentries: 50,
filters: {
getpkgs: () => {
let pkgs = [];
let other = [];
for (let i in packages) {
if (! Browser.filters.isfiltered(packages[i].categories)) {
pkgs.push(packages[i]);
} else {
other.push(packages[i]);
}
}
return pkgs;
},
get: () => {
let filtered = [];
let unfiltered = [];
let checks = browser.querySelectorAll("#filters .check");
for (let i = 0; i < checks.length; i++) {
if (! checks[i].classList.contains("checked")) {
filtered.push(checks[i].getAttribute("value"));
} else {
unfiltered.push(checks[i].getAttribute("value"));
}
}
return {
filtered,
unfiltered
};
},
isfiltered: (categories) => {
let filtered = Browser.filters.get().filtered;
let unfiltered = Browser.filters.get().unfiltered;
let state = false;
let filters = [
"Mods", "Skins",
"Client-side", "Server-side",
];
let newcategories = [];
for (let i = 0; i < categories.length; i++) {
if (filters.includes(categories[i])) {
newcategories.push(categories[i]);
}
}; categories = newcategories;
if (categories.length == 0) {return true}
for (let i = 0; i < categories.length; i++) {
if (filtered.includes(categories[i])) {
state = true;
continue
} else if (unfiltered.includes(categories[i])) {
state = false;
continue
}
state = true;
}
return state;
},
toggle: (state) => {
if (state == false) {
filters.classList.remove("shown");
return
}
filters.classList.toggle("shown");
let filterRect = filter.getBoundingClientRect();
let spacing = parseInt(getComputedStyle(filters).getPropertyValue("--spacing"));
filters.style.top = filterRect.bottom - spacing;
filters.style.right = filterRect.right - filterRect.left + filterRect.width - (spacing / 2);
},
},
toggle: (state) => {
if (state) {
browser.scrollTo(0, 0);
overlay.classList.add("shown");
browser.classList.add("shown");
if (browserEntries.querySelectorAll(".el").length == 0) {
Browser.loadfront();
}
return
} else if (! state) {
if (state != undefined) {
Browser.filters.toggle(false);
overlay.classList.remove("shown");
browser.classList.remove("shown");
preview.classList.remove("shown");
return
}
}
browser.scrollTo(0, 0);
overlay.classList.toggle("shown");
browser.classList.toggle("shown");
},
loadfront: async () => {
Browser.loading();
packagecount = 0;
if (packages.length < 1) {
packages = await (await fetch("https://northstar.thunderstore.io/api/v1/package/")).json();
fuse = new Fuse(packages, {
keys: ["full_name"]
})
}
let pkgs = Browser.filters.getpkgs();
for (let i in pkgs) {
if (packagecount >= Browser.maxentries) {
Browser.endoflist();
break
}
new BrowserElFromObj(pkgs[i]);
packagecount++;
}
},
loading: (string) => {
if (Browser.filters.get().unfiltered.length == 0) {
string = lang("gui.browser.noresults");
}
if (string) {
browserEntries.innerHTML = `
${properties.title}
${properties.description}
`
browserEntries.appendChild(entry);
}
let recent_toasts = {};
function add_recent_toast(name, timeout = 3000) {
if (recent_toasts[name]) {return}
recent_toasts[name] = true;
setTimeout(() => {
delete recent_toasts[name];
}, timeout)
}
ipcRenderer.on("removed-mod", (event, mod) => {
setButtons(true);
Browser.setbutton(mod.name, lang("gui.browser.install"));
if (mod.manifestname) {
Browser.setbutton(mod.manifestname, lang("gui.browser.install"));
}
})
ipcRenderer.on("failed-mod", (event, modname) => {
if (recent_toasts["failed" + modname]) {return}
add_recent_toast("failed" + modname);
setButtons(true);
new Toast({
timeout: 10000,
scheme: "error",
title: lang("gui.toast.title.failed"),
description: lang("gui.toast.desc.failed")
})
})
ipcRenderer.on("duped-mod", (event, modname) => {
if (recent_toasts["duped" + modname]) {return}
add_recent_toast("duped" + modname);
setButtons(true);
new Toast({
timeout: 10000,
scheme: "warning",
title: lang("gui.toast.title.duped"),
description: modname + " " + lang("gui.toast.desc.duped")
})
})
ipcRenderer.on("no-internet", (event, modname) => {
setButtons(true);
new Toast({
timeout: 10000,
scheme: "error",
title: lang("gui.toast.noInternet.title"),
description: lang("gui.toast.noInternet.desc")
})
})
ipcRenderer.on("installed-mod", (event, mod) => {
if (recent_toasts["installed" + mod.name]) {return}
add_recent_toast("installed" + mod.name);
setButtons(true);
Browser.setbutton(mod.name, lang("gui.browser.reinstall"));
if (mod.malformed) {
new Toast({
timeout: 8000,
scheme: "warning",
title: lang("gui.toast.title.malformed"),
description: mod.name + " " + lang("gui.toast.desc.malformed")
})
}
new Toast({
scheme: "success",
title: lang("gui.toast.title.installed"),
description: mod.name + " " + lang("gui.toast.desc.installed")
})
if (installqueue.length != 0) {
installFromURL("https://thunderstore.io/package/download/" + installqueue[0]);
installqueue.shift();
}
})
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 = "";
search.addEventListener("keyup", () => {
Browser.filters.toggle(false);
clearTimeout(searchtimeout);
if (searchstr != search.value) {
if (search.value.replaceAll(" ", "") == "") {
searchstr = "";
Browser.loadfront();
return
}
searchtimeout = setTimeout(() => {
Browser.search(search.value);
searchstr = search.value;
}, 500)
}
})
let events = ["scroll", "mousedown", "touchdown"];
events.forEach((event) => {
browser.addEventListener(event, () => {
Preview.hide();
let mouseAt = document.elementsFromPoint(mouseX, mouseY);
if (! mouseAt.includes(document.querySelector("#filter"))
&& ! mouseAt.includes(document.querySelector(".overlay"))) {
Browser.filters.toggle(false);
}
})
});
view.addEventListener("dom-ready", () => {
let css = [
fs.readFileSync(__dirname + "/css/theming.css", "utf8"),
fs.readFileSync(__dirname + "/css/webview.css", "utf8")
]
view.insertCSS(css.join(" "));
})
view.addEventListener("did-stop-loading", () => {
view.style.display = "flex";
setTimeout(() => {
view.classList.remove("loading");
}, 200)
})
view.addEventListener("did-start-loading", () => {
view.style.display = "none";
view.classList.add("loading");
})
let mouseY = 0;
let mouseX = 0;
browser.addEventListener("mousemove", (event) => {
mouseY = event.clientY;
mouseX = event.clientX;
})
let checks = document.querySelectorAll(".check");
for (let i = 0; i < checks.length; i++) {
checks[i].setAttribute("onclick",
"this.classList.toggle('checked');Browser.loadfront();search.value = ''"
)
}