diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..064214d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,29 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es2021": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 13 + }, + "rules": { + "indent": [ + "error", + 4 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "never" + ] + } +} diff --git a/package.json b/package.json index e5efc86..9c0eb1a 100644 --- a/package.json +++ b/package.json @@ -9,5 +9,8 @@ "build-win": ".\\build_win.cmd", "build-linux": "./build.sh", "build": "echo !! Run build-win or build-linux to build for your platform !!\n" + }, + "devDependencies": { + "eslint": "^8.14.0" } } diff --git a/resources/js/authAlert.js b/resources/js/authAlert.js index c6b806e..9580530 100644 --- a/resources/js/authAlert.js +++ b/resources/js/authAlert.js @@ -1,45 +1,45 @@ let alertTimeout, alertCooldown = 3000 async function displayLoginAlert(message, type, cooldown = null) { - displayAlert(message, type, cooldown, 'login') + displayAlert(message, type, cooldown, 'login') } async function displayRegisterAlert(message, type, cooldown = null) { - displayAlert(message, type, cooldown, 'register') + displayAlert(message, type, cooldown, 'register') } function displayAlert(message, type, cooldown, name) { - const elm = document.getElementById(`${name}Alert`); - const text = document.getElementById(`${name}AlertText`); + const elm = document.getElementById(`${name}Alert`) + const text = document.getElementById(`${name}AlertText`) - elm.style.removeProperty('display'); + elm.style.removeProperty('display') - // Remove classification classes - elm.classList.remove('error'); - elm.classList.remove('success'); - elm.classList.remove('warn'); + // Remove classification classes + elm.classList.remove('error') + elm.classList.remove('success') + elm.classList.remove('warn') - switch(type) { + switch(type) { case 'error': - elm.classList.add('error'); - break; + elm.classList.add('error') + break case 'success': - elm.classList.add('success'); - break; + elm.classList.add('success') + break case 'warn': default: - elm.classList.add('warn'); - break; - } + elm.classList.add('warn') + break + } - text.innerText = message; + text.innerText = message - clearTimeout(alertTimeout) + clearTimeout(alertTimeout) - // Disappear after cooldown - alertTimeout = setTimeout(() => { - elm.style.display = 'none'; - }, cooldown || alertCooldown) + // Disappear after cooldown + alertTimeout = setTimeout(() => { + elm.style.display = 'none' + }, cooldown || alertCooldown) } \ No newline at end of file diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index e45a0f4..bcc6e7a 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -1,102 +1,102 @@ async function clearGCInstallation() { - Neutralino.os.execCommand(`del /s /q "./gc"`) + Neutralino.os.execCommand('del /s /q "./gc"') } async function setDownloadButtonsToLoading() { - const stableBtn = document.querySelector('#stableInstall') - const devBtn = document.querySelector('#devInstall') + const stableBtn = document.querySelector('#stableInstall') + const devBtn = document.querySelector('#devInstall') - stableBtn.innerText = localeObj.gcScriptRunning || 'Running...' + stableBtn.innerText = localeObj.gcScriptRunning || 'Running...' - devBtn.innerText = localeObj.gcScriptRunning || 'Running...' + devBtn.innerText = localeObj.gcScriptRunning || 'Running...' - // Set btns to disabled - stableBtn.disabled = true - stableBtn.classList.add('disabled') + // Set btns to disabled + stableBtn.disabled = true + stableBtn.classList.add('disabled') - devBtn.disabled = true - devBtn.classList.add('disabled') + devBtn.disabled = true + devBtn.classList.add('disabled') } async function resetDownloadButtons() { - const stableBtn = document.querySelector('#stableInstall') - const devBtn = document.querySelector('#devInstall') + const stableBtn = document.querySelector('#stableInstall') + const devBtn = document.querySelector('#devInstall') - stableBtn.innerText = localeObj.stableInstall || 'Download' - devBtn.innerText = localeObj.devInstall || 'Download' + stableBtn.innerText = localeObj.stableInstall || 'Download' + devBtn.innerText = localeObj.devInstall || 'Download' - // Set btns to enabled - stableBtn.disabled = false - stableBtn.classList.remove('disabled') + // Set btns to enabled + stableBtn.disabled = false + stableBtn.classList.remove('disabled') - devBtn.disabled = false - devBtn.classList.remove('disabled') + devBtn.disabled = false + devBtn.classList.remove('disabled') } async function downloadGC(branch) { - const config = await getCfg() + const config = await getCfg() - // If we are pulling from a new branch, delete the old installation - if (config.grasscutterBranch !== branch) await clearGCInstallation() + // If we are pulling from a new branch, delete the old installation + if (config.grasscutterBranch !== branch) await clearGCInstallation() - // Set current installation in config - config.grasscutterBranch = branch + // Set current installation in config + config.grasscutterBranch = branch - // Set gc path for people with launcher enabled - config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` + // Set gc path for people with launcher enabled + config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` - // Enable server launcher - config.serverLaunchPanel = true + // Enable server launcher + config.serverLaunchPanel = true - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) - setDownloadButtonsToLoading() + setDownloadButtonsToLoading() - // Keystore for branch (since they can differ) - const keystoreUrl = `https://github.com/Grasscutters/Grasscutter/raw/${branch}/keystore.p12` + // Keystore for branch (since they can differ) + const keystoreUrl = `https://github.com/Grasscutters/Grasscutter/raw/${branch}/keystore.p12` - // External service that allows un-authed artifact downloading - const artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip` + // External service that allows un-authed artifact downloading + const artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip` - // For data files - const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`) - const dataList = dataFiles.data - .map(file => ({ path: file.path, filename: file.name })) - .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + // For data files + const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`) + const dataList = dataFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) - // For key files - const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`) - const keyList = keyFiles.data - .map(file => ({ path: file.path, filename: file.name })) - .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + // For key files + const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`) + const keyList = keyFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) - const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') + const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') - // Ensure data and key folders exist + // Ensure data and key folders exist - await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`) - await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`) + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`) + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`) - // Download data files - for (const o of dataList) { - const folder = 'data' - await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) - } + // Download data files + for (const o of dataList) { + const folder = 'data' + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } - // Download key files - for (const o of keyList) { - const folder = 'keys' - await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) - } + // Download key files + for (const o of keyList) { + const folder = 'keys' + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } - // Run installer - createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + // Run installer + createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) - // Fix buttons - resetDownloadButtons() + // Fix buttons + resetDownloadButtons() - // Display folder after saving config - displayServerFolder() - enableServerButton() - displayServerLaunchSection() + // Display folder after saving config + displayServerFolder() + enableServerButton() + displayServerLaunchSection() } \ No newline at end of file diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 4e3a38b..a4f514d 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -3,28 +3,28 @@ * * @returns {Promise} */ - async function getCfg() { - const defaultConf = { - gameexe: '', - serverFolder: '', - lastConnect: '', - enableKillswitch: false, - serverLaunchPanel: false, - language: 'en', - useHttps: true, - grasscutterBranch: '', - } - const cfgStr = await Neutralino.storage.getData('config').catch(e => { +async function getCfg() { + const defaultConf = { + gameexe: '', + serverFolder: '', + lastConnect: '', + enableKillswitch: false, + serverLaunchPanel: false, + language: 'en', + useHttps: true, + grasscutterBranch: '', + } + const cfgStr = await Neutralino.storage.getData('config').catch(e => { // The data isn't set, so this is our first time opening - Neutralino.storage.setData('config', JSON.stringify(defaultConf)) + Neutralino.storage.setData('config', JSON.stringify(defaultConf)) - // Show the first time notice if there is no config - document.querySelector('#firstTimeNotice').style.display = 'block' - }) + // Show the first time notice if there is no config + document.querySelector('#firstTimeNotice').style.display = 'block' + }) - const config = cfgStr ? JSON.parse(cfgStr) : defaultConf + const config = cfgStr ? JSON.parse(cfgStr) : defaultConf - return config + return config } /** @@ -32,91 +32,91 @@ * * @returns {Promise} */ - async function getFavIps() { - const ipStr = await Neutralino.storage.getData('favorites').catch(e => { +async function getFavIps() { + const ipStr = await Neutralino.storage.getData('favorites').catch(e => { // The data isn't set, so this is our first time opening - Neutralino.storage.setData('favorites', JSON.stringify([])) - }) + Neutralino.storage.setData('favorites', JSON.stringify([])) + }) - const ipArr = ipStr ? JSON.parse(ipStr) : [] + const ipArr = ipStr ? JSON.parse(ipStr) : [] - return ipArr + return ipArr } async function proxyIsInstalled() { - // Check if the proxy server is installed - const curDirList = await filesystem.readDirectory(NL_CWD) + // Check if the proxy server is installed + const curDirList = await filesystem.readDirectory(NL_CWD) - if (curDirList.find(f => f.entry === 'ext')) { - const extFiles = await filesystem.readDirectory(NL_CWD + '/ext') + if (curDirList.find(f => f.entry === 'ext')) { + const extFiles = await filesystem.readDirectory(NL_CWD + '/ext') - if (extFiles.find(f => f.entry === 'mitmdump.exe')) { - return true + if (extFiles.find(f => f.entry === 'mitmdump.exe')) { + return true + } } - } - return false + return false } async function checkForUpdates() { - const url = 'https://api.github.com/repos/Grasscutters/GrassClipper/releases/latest' + const url = 'https://api.github.com/repos/Grasscutters/GrassClipper/releases/latest' - const { data } = await axios.get(url) - const latest = data.tag_name + const { data } = await axios.get(url) + const latest = data.tag_name - return latest + return latest } async function displayUpdate() { - const latest = await checkForUpdates() - const versionDisplay = document.querySelector('#newestVersion') - const notif = document.querySelector('#downloadNotif') + const latest = await checkForUpdates() + const versionDisplay = document.querySelector('#newestVersion') + const notif = document.querySelector('#downloadNotif') - if (latest === `v${NL_APPVERSION}`) return + if (latest === `v${NL_APPVERSION}`) return - versionDisplay.innerText = latest + versionDisplay.innerText = latest - notif.classList.add('displayed') + notif.classList.add('displayed') - setTimeout(() => { - notif.classList.remove('displayed') - }, 5000) + setTimeout(() => { + notif.classList.remove('displayed') + }, 5000) } async function openLatestDownload() { - const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/' + const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/' - Neutralino.os.open(downloadLink) + Neutralino.os.open(downloadLink) } async function openGameFolder() { - const config = await getCfg() - const folder = config.gameexe.match(/.*\\/g, '')[0] + const config = await getCfg() + const folder = config.gameexe.match(/.*\\/g, '')[0] - openInExplorer(folder) + openInExplorer(folder) } async function openGrasscutterFolder() { - const config = await getCfg() - const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] + const config = await getCfg() + const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] - openInExplorer(folder) + openInExplorer(folder) } /** * Minimize the window */ - function minimizeWin() { - console.log('min') - Neutralino.window.minimize() +function minimizeWin() { + console.log('min') + Neutralino.window.minimize() } /** * Close the window */ function closeWin() { - console.log('close') - Neutralino.app.exit() + console.log('close') + Neutralino.app.exit() - window.close() + window.close() } diff --git a/resources/js/hoverEvt.js b/resources/js/hoverEvt.js index 47adb2c..af98ea0 100644 --- a/resources/js/hoverEvt.js +++ b/resources/js/hoverEvt.js @@ -1,36 +1,36 @@ document.addEventListener('DOMContentLoaded', async () => { - const firstPanel = document.querySelector('#firstPanel') - const secondPanel = document.querySelector('#secondPanel') - const thirdPanel = document.querySelector('#thirdPanel') + const firstPanel = document.querySelector('#firstPanel') + const secondPanel = document.querySelector('#secondPanel') + const thirdPanel = document.querySelector('#thirdPanel') - // Listen to hovers - firstPanel.addEventListener('mouseover', () => { - secondPanel.classList.add('darken') - thirdPanel.classList.add('darken') - }) + // Listen to hovers + firstPanel.addEventListener('mouseover', () => { + secondPanel.classList.add('darken') + thirdPanel.classList.add('darken') + }) - firstPanel.addEventListener('mouseout', () => { - secondPanel.classList.remove('darken') - thirdPanel.classList.remove('darken') - }) + firstPanel.addEventListener('mouseout', () => { + secondPanel.classList.remove('darken') + thirdPanel.classList.remove('darken') + }) - secondPanel.addEventListener('mouseover', () => { - firstPanel.classList.add('darken') - thirdPanel.classList.add('darken') - }) + secondPanel.addEventListener('mouseover', () => { + firstPanel.classList.add('darken') + thirdPanel.classList.add('darken') + }) - secondPanel.addEventListener('mouseout', () => { - firstPanel.classList.remove('darken') - thirdPanel.classList.remove('darken') - }) + secondPanel.addEventListener('mouseout', () => { + firstPanel.classList.remove('darken') + thirdPanel.classList.remove('darken') + }) - thirdPanel.addEventListener('mouseover', () => { - firstPanel.classList.add('darken') - secondPanel.classList.add('darken') - }) + thirdPanel.addEventListener('mouseover', () => { + firstPanel.classList.add('darken') + secondPanel.classList.add('darken') + }) - thirdPanel.addEventListener('mouseout', () => { - firstPanel.classList.remove('darken') - secondPanel.classList.remove('darken') - }) + thirdPanel.addEventListener('mouseout', () => { + firstPanel.classList.remove('darken') + secondPanel.classList.remove('darken') + }) }) \ No newline at end of file diff --git a/resources/js/index.js b/resources/js/index.js index a9a0bee..822fb67 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -1,187 +1,187 @@ -Neutralino.init(); +Neutralino.init() -let localeObj; +let localeObj const filesystem = Neutralino.filesystem const createCmdWindow = async (command) => { - Neutralino.os.execCommand(`cmd.exe /c start "" ${command}`, { background: true }) + Neutralino.os.execCommand(`cmd.exe /c start "" ${command}`, { background: true }) } const openInExplorer = async (path) => { - console.log(`explorer.exe "${path}"`) - createCmdWindow(`explorer.exe "${path}"`) + console.log(`explorer.exe "${path}"`) + createCmdWindow(`explorer.exe "${path}"`) } /** * Enable play buttons */ async function enableButtons() { - const offBtn = document.querySelector('#playOfficial') - const privBtn = document.querySelector('#playPrivate') + const offBtn = document.querySelector('#playOfficial') + const privBtn = document.querySelector('#playPrivate') - offBtn.classList.remove('disabled') - offBtn.disabled = false + offBtn.classList.remove('disabled') + offBtn.disabled = false - // Check if the proxy server is installed - if (await proxyIsInstalled()) { - privBtn.classList.remove('disabled') - privBtn.disabled = false - } + // Check if the proxy server is installed + if (await proxyIsInstalled()) { + privBtn.classList.remove('disabled') + privBtn.disabled = false + } } /** * Enable server launch button */ - async function enableServerButton() { - const serverBtn = document.querySelector('#serverLaunch') +async function enableServerButton() { + const serverBtn = document.querySelector('#serverLaunch') - serverBtn.classList.remove('disabled') - serverBtn.disabled = false + serverBtn.classList.remove('disabled') + serverBtn.disabled = false } /** * Disable buttons when the game folder is not set */ async function handleGameNotSet() { - // Set buttons to greyed out and disable - document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet + // Set buttons to greyed out and disable + document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet - // Set official server background to default - document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` + // Set official server background to default + document.querySelector('#firstPanel').style.backgroundImage = 'url("../bg/private/default.png")' - const offBtn = document.querySelector('#playOfficial') - const privBtn = document.querySelector('#playPrivate') + const offBtn = document.querySelector('#playOfficial') + const privBtn = document.querySelector('#playPrivate') - offBtn.classList.add('disabled') - offBtn.disabled = true + offBtn.classList.add('disabled') + offBtn.disabled = true - privBtn.classList.add('disabled') - privBtn.disabled = true + privBtn.classList.add('disabled') + privBtn.disabled = true - // TODO show a dialog of sorts + // TODO show a dialog of sorts } async function handleServerNotSet() { - // Set buttons to greyed out and disable - document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet + // Set buttons to greyed out and disable + document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet - // Set official server background to default - // document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` + // Set official server background to default + // document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` - const privBtn = document.querySelector('#serverLaunch') + const privBtn = document.querySelector('#serverLaunch') - privBtn.classList.add('disabled') - privBtn.disabled = true + privBtn.classList.add('disabled') + privBtn.disabled = true } /** * Show the game folder under the select button */ async function displayGameFolder() { - const elm = document.querySelector('#gamePath') - const config = await getCfg() + const elm = document.querySelector('#gamePath') + const config = await getCfg() - elm.innerHTML = config.gameexe + elm.innerHTML = config.gameexe } /** * Show the server folder under the select button */ - async function displayServerFolder() { - const elm = document.querySelector('#serverPath') - const config = await getCfg() +async function displayServerFolder() { + const elm = document.querySelector('#serverPath') + const config = await getCfg() - elm.innerHTML = config.serverFolder + elm.innerHTML = config.serverFolder } /** * Set the background images of both the private and public sections */ async function setBackgroundImage() { - const config = await getCfg() + const config = await getCfg() - const privImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/private')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) - const privImage = privImages[Math.floor(Math.random() * privImages.length)].entry + const privImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/private')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) + const privImage = privImages[Math.floor(Math.random() * privImages.length)].entry - const servImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/server')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) - const servImage = servImages[Math.floor(Math.random() * servImages.length)].entry + const servImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/server')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) + const servImage = servImages[Math.floor(Math.random() * servImages.length)].entry - // Set default image, it will change if the bg folder exists - document.querySelector('#firstPanel').style.backgroundImage = `url("https://webstatic.hoyoverse.com/upload/event/2020/11/04/7fd661b5184e1734f91f628b6f89a31f_7367318474207189623.png")` + // Set default image, it will change if the bg folder exists + document.querySelector('#firstPanel').style.backgroundImage = 'url("https://webstatic.hoyoverse.com/upload/event/2020/11/04/7fd661b5184e1734f91f628b6f89a31f_7367318474207189623.png")' - // Set the private background image - document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")` + // Set the private background image + document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")` - // Set the server background image - document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")` + // Set the server background image + document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")` - return + return - // Check if resources folder exists - const mainDir = await filesystem.readDirectory(NL_CWD) - if (!mainDir.find(dir => dir.entry === 'resources')) { - await filesystem.createDirectory(NL_CWD + '/resources') - } - - // Ensure bg folder exists - const bgDir = await filesystem.readDirectory(NL_CWD + '/resources') - if (!bgDir.find(dir => dir.entry === 'bg')) { - await filesystem.createDirectory(NL_CWD + '/resources/bg') - } - - // Ensure official folder exists - const officialDir = await filesystem.readDirectory(NL_CWD + '/resources/bg') - if (!officialDir.find(dir => dir.entry === 'official')) { - await filesystem.createDirectory(NL_CWD + '/resources/bg/official') - } - - if (config.gameexe) { - // See if bg folder exists in parent dir - const parentDir = await filesystem.readDirectory(config.gameexe + '/..') - - if (parentDir.find(dir => dir.entry === 'bg')) { - - const officialImages = (await filesystem.readDirectory(config.gameexe + '/../bg')).filter(file => file.type === 'FILE') - - if (officialImages.length > 0) { - for (const bg of officialImages) { - const path = config.gameexe.replace('\\', '/') + '/../bg/' + bg.entry - - // See if the file exists already - const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE') - - if (!currentBgs.find(file => file.entry === bg.entry)) { - await filesystem.copyFile(path, NL_CWD + '/resources/bg/official/' + bg.entry).catch(e => { - // TODO: Handle error - }) - } - } - - // Pick one of the images - const localImg = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official')).filter(file => file.type === 'FILE') - const image = localImg[Math.floor(Math.random() * localImg.length)].entry - - // Set background image - document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/official/${image}")` - } + // Check if resources folder exists + const mainDir = await filesystem.readDirectory(NL_CWD) + if (!mainDir.find(dir => dir.entry === 'resources')) { + await filesystem.createDirectory(NL_CWD + '/resources') + } + + // Ensure bg folder exists + const bgDir = await filesystem.readDirectory(NL_CWD + '/resources') + if (!bgDir.find(dir => dir.entry === 'bg')) { + await filesystem.createDirectory(NL_CWD + '/resources/bg') + } + + // Ensure official folder exists + const officialDir = await filesystem.readDirectory(NL_CWD + '/resources/bg') + if (!officialDir.find(dir => dir.entry === 'official')) { + await filesystem.createDirectory(NL_CWD + '/resources/bg/official') + } + + if (config.gameexe) { + // See if bg folder exists in parent dir + const parentDir = await filesystem.readDirectory(config.gameexe + '/..') + + if (parentDir.find(dir => dir.entry === 'bg')) { + + const officialImages = (await filesystem.readDirectory(config.gameexe + '/../bg')).filter(file => file.type === 'FILE') + + if (officialImages.length > 0) { + for (const bg of officialImages) { + const path = config.gameexe.replace('\\', '/') + '/../bg/' + bg.entry + + // See if the file exists already + const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE') + + if (!currentBgs.find(file => file.entry === bg.entry)) { + await filesystem.copyFile(path, NL_CWD + '/resources/bg/official/' + bg.entry).catch(e => { + // TODO: Handle error + }) + } + } + + // Pick one of the images + const localImg = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official')).filter(file => file.type === 'FILE') + const image = localImg[Math.floor(Math.random() * localImg.length)].entry + + // Set background image + document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/official/${image}")` + } + } } - } } /** * When an IP is being input, check if it is part of the favorites */ async function handleFavoriteInput() { - const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value || '443' - const ipArr = await getFavIps() + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value || '443' + const ipArr = await getFavIps() - const addr = `${ip}:${port}` + const addr = `${ip}:${port}` - if (!ip || !ipArr.includes(addr)) { - document.querySelector('#star').src = 'icons/star_empty.svg' - } else { - document.querySelector('#star').src = 'icons/star_filled.svg' - } + if (!ip || !ipArr.includes(addr)) { + document.querySelector('#star').src = 'icons/star_empty.svg' + } else { + document.querySelector('#star').src = 'icons/star_filled.svg' + } } /** @@ -190,182 +190,182 @@ async function handleFavoriteInput() { * @param {String} ip */ async function setIp(ip) { - const ipInput = document.querySelector('#ip') - const portInput = document.querySelector('#port') + const ipInput = document.querySelector('#ip') + const portInput = document.querySelector('#port') - const parseIp = ip.split(':')[0] - const parsePort = ip.split(':')[1] + const parseIp = ip.split(':')[0] + const parsePort = ip.split(':')[1] - // Set star - if (ip) { - document.querySelector('#star').src = 'icons/star_filled.svg' - } + // Set star + if (ip) { + document.querySelector('#star').src = 'icons/star_filled.svg' + } - ipInput.value = parseIp - portInput.value = parsePort + ipInput.value = parseIp + portInput.value = parsePort } /** * Create/hide the favorites list */ async function handleFavoriteList() { - const ipArr = await getFavIps() - const ipList = document.querySelector('#ipList') + const ipArr = await getFavIps() + const ipList = document.querySelector('#ipList') - if (ipList.style.display === 'none') { - ipList.innerHTML = '' + if (ipList.style.display === 'none') { + ipList.innerHTML = '' - const list = ipList.appendChild( - document.createElement('ul') - ) + const list = ipList.appendChild( + document.createElement('ul') + ) - if (ipArr.length < 1) { - const listItem = list.appendChild( - document.createElement('li') - ) + if (ipArr.length < 1) { + const listItem = list.appendChild( + document.createElement('li') + ) - listItem.innerHTML = localeObj.noFavorites + listItem.innerHTML = localeObj.noFavorites + } + + for (const ip of ipArr) { + const elm = document.createElement('li') + elm.innerHTML = ip + elm.addEventListener('click', () => setIp(ip)) + list.appendChild(elm) + } + + ipList.style.display = 'block' + + const transform = window.getComputedStyle(document.querySelector('#ipList')).transform + const xy = [ transform.split(',')[4], transform.split(',')[5] ] + let newY = (27 * ipArr.length) * window.devicePixelRatio + + if (ipArr.length === 0 || ipArr.length === 1) newY = 0 + + ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)` } - - for (const ip of ipArr) { - const elm = document.createElement('li') - elm.innerHTML = ip - elm.addEventListener('click', () => setIp(ip)) - list.appendChild(elm) - } - - ipList.style.display = 'block' - - const transform = window.getComputedStyle(document.querySelector('#ipList')).transform - const xy = [ transform.split(',')[4], transform.split(',')[5] ] - let newY = (27 * ipArr.length) * window.devicePixelRatio - - if (ipArr.length === 0 || ipArr.length === 1) newY = 0 - - ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)` - } } async function openDownloads() { - const downloads = document.querySelector('#downloadPanel') - const config = await getCfg() + const downloads = document.querySelector('#downloadPanel') + const config = await getCfg() - if (downloads.style.display === 'none') { - downloads.style.removeProperty('display') - } + if (downloads.style.display === 'none') { + downloads.style.removeProperty('display') + } - // Disable the resource download button if a serverFolder path is not set - if (!config.serverFolder) { - document.querySelector('#resourceInstall').disabled = true - document.querySelector('#resourceInstall').classList.add('disabled') - } else { - document.querySelector('#resourceInstall').disabled = false - document.querySelector('#resourceInstall').classList.remove('disabled') - } + // Disable the resource download button if a serverFolder path is not set + if (!config.serverFolder) { + document.querySelector('#resourceInstall').disabled = true + document.querySelector('#resourceInstall').classList.add('disabled') + } else { + document.querySelector('#resourceInstall').disabled = false + document.querySelector('#resourceInstall').classList.remove('disabled') + } } async function closeDownloads() { - const downloads = document.querySelector('#downloadPanel') + const downloads = document.querySelector('#downloadPanel') - downloads.style.display = 'none' + downloads.style.display = 'none' } async function openSettings() { - const settings = document.querySelector('#settingsPanel') - const config = await getCfg() + const settings = document.querySelector('#settingsPanel') + const config = await getCfg() - if (settings.style.display === 'none') { - settings.style.removeProperty('display') - } + if (settings.style.display === 'none') { + settings.style.removeProperty('display') + } - // Fill setting options with what is currently set in config - const killSwitch = document.querySelector('#killswitchOption') - const serverLaunch = document.querySelector('#serverLaunchOption') - const httpsCheckbox = document.querySelector('#httpsOption') + // Fill setting options with what is currently set in config + const killSwitch = document.querySelector('#killswitchOption') + const serverLaunch = document.querySelector('#serverLaunchOption') + const httpsCheckbox = document.querySelector('#httpsOption') - killSwitch.checked = config.enableKillswitch - serverLaunch.checked = config.serverLaunchPanel - httpsCheckbox.checked = config.useHttps + killSwitch.checked = config.enableKillswitch + serverLaunch.checked = config.serverLaunchPanel + httpsCheckbox.checked = config.useHttps - // Load languages - getLanguages() + // Load languages + getLanguages() - // Check for updates - //checkForUpdatesAndShow() + // Check for updates + //checkForUpdatesAndShow() } async function closeSettings() { - const settings = document.querySelector('#settingsPanel') - const config = await getCfg() + const settings = document.querySelector('#settingsPanel') + const config = await getCfg() - settings.style.display = 'none' + settings.style.display = 'none' - // In case we installed the proxy server - if (await proxyIsInstalled() && config.gameexe) { - const playPriv = document.querySelector('#playPrivate') + // In case we installed the proxy server + if (await proxyIsInstalled() && config.gameexe) { + const playPriv = document.querySelector('#playPrivate') - playPriv.classList.remove('disabled') - playPriv.disabled = false - } + playPriv.classList.remove('disabled') + playPriv.disabled = false + } } async function openLogin() { - const login = document.querySelector('#loginPanel') - const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value - const loginIpDisplay = document.querySelector('#loginPopupServer') - const registerIpDisplay = document.querySelector('#registerPopupServer') + const login = document.querySelector('#loginPanel') + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value + const loginIpDisplay = document.querySelector('#loginPopupServer') + const registerIpDisplay = document.querySelector('#registerPopupServer') - const config = await getCfg() - const useHttps = config.useHttps - const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`; + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` - // Check if we even need to authenticate - try { - const { data } = await axios.get(url + '/authentication/type') + // Check if we even need to authenticate + try { + const { data } = await axios.get(url + '/authentication/type') - if (!data.includes('GCAuthAuthenticationHandler')) { - launchPrivate() - return + if (!data.includes('GCAuthAuthenticationHandler')) { + launchPrivate() + return + } + } catch(e) { + launchPrivate() + return } - } catch(e) { - launchPrivate() - return - } - loginIpDisplay.innerText = ip - registerIpDisplay.innerText = ip + loginIpDisplay.innerText = ip + registerIpDisplay.innerText = ip - if (login.style.display === 'none') { - login.style.removeProperty('display') - } + if (login.style.display === 'none') { + login.style.removeProperty('display') + } } async function closeLogin() { - const login = document.querySelector('#loginPanel') + const login = document.querySelector('#loginPanel') - login.style.display = 'none' + login.style.display = 'none' - setLoginSection() + setLoginSection() } async function closeFirstTimePopup() { - const firstTimePopup = document.querySelector('#firstTimeNotice') - firstTimePopup.style.display = 'none' + const firstTimePopup = document.querySelector('#firstTimeNotice') + firstTimePopup.style.display = 'none' } async function runInstallScript() { - createCmdWindow(`.\\scripts\\install.cmd "${NL_CWD}" true`) + createCmdWindow(`.\\scripts\\install.cmd "${NL_CWD}" true`) - // Create an interval that will check for the proxy server installation finish - const interval = setInterval(async () => { - if (await proxyIsInstalled()) { - clearInterval(interval) - enableButtons() - } - }, 1000) + // Create an interval that will check for the proxy server installation finish + const interval = setInterval(async () => { + if (await proxyIsInstalled()) { + clearInterval(interval) + enableButtons() + } + }, 1000) - closeFirstTimePopup() + closeFirstTimePopup() } async function updateResources() { @@ -373,109 +373,109 @@ async function updateResources() { } async function checkForUpdatesAndShow() { - const updateBtn = document.querySelector('#updateBtn') - const subtitle = document.querySelector('#updateSubtitle') - const url = 'https://github.com/Grasscutters/GrassClipper/releases/latest/download/' - const manifest = await Neutralino.updater.checkForUpdates(url) + const updateBtn = document.querySelector('#updateBtn') + const subtitle = document.querySelector('#updateSubtitle') + const url = 'https://github.com/Grasscutters/GrassClipper/releases/latest/download/' + const manifest = await Neutralino.updater.checkForUpdates(url) - // Version mismatch? Update! - if (manifest?.version !== NL_APPVERSION) { - subtitle.innerHTML = "New update available!" - updateBtn.classList.remove('disabled') - } else { - subtitle.innerHTML = "You are on the latest version! :)" - updateBtn.classList.add('disabled') - } + // Version mismatch? Update! + if (manifest?.version !== NL_APPVERSION) { + subtitle.innerHTML = 'New update available!' + updateBtn.classList.remove('disabled') + } else { + subtitle.innerHTML = 'You are on the latest version! :)' + updateBtn.classList.add('disabled') + } } async function displayServerLaunchSection() { - const serverPanel = document.querySelector('#thirdPanel') - const bottomBtnSection = document.querySelector('#serverPath').parentElement + const serverPanel = document.querySelector('#thirdPanel') + const bottomBtnSection = document.querySelector('#serverPath').parentElement - if (serverPanel.style.display === 'none') { - serverPanel.style.removeProperty('display') - bottomBtnSection.style.removeProperty('display') - } else { - serverPanel.style.display = 'none' - bottomBtnSection.style.display = 'none' - } + if (serverPanel.style.display === 'none') { + serverPanel.style.removeProperty('display') + bottomBtnSection.style.removeProperty('display') + } else { + serverPanel.style.display = 'none' + bottomBtnSection.style.display = 'none' + } } /** * Set the game folder by opening a folder picker */ async function setGameExe() { - const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, { - filters: [ - { name: 'Executable files', extensions: ['exe'] } - ] - }) + const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, { + filters: [ + { name: 'Executable files', extensions: ['exe'] } + ] + }) - if (!gameExe[0]) return; + if (!gameExe[0]) return - // Set the folder in our configuration - const config = await getCfg() + // Set the folder in our configuration + const config = await getCfg() - // It's an array of selections, so only get the first one - config.gameexe = gameExe[0].replace(/\//g, '\\') + // It's an array of selections, so only get the first one + config.gameexe = gameExe[0].replace(/\//g, '\\') - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) - // Refresh background and path - setBackgroundImage() - displayGameFolder() - enableButtons() + // Refresh background and path + setBackgroundImage() + displayGameFolder() + enableButtons() } async function setGrasscutterFolder() { - const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, { - filters: [ - { name: 'Jar files', extensions: ['jar'] } - ] - }) + const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, { + filters: [ + { name: 'Jar files', extensions: ['jar'] } + ] + }) - if (!folder[0]) return; + if (!folder[0]) return - // Set the folder in our configuration - const config = await getCfg() + // Set the folder in our configuration + const config = await getCfg() - config.serverFolder = folder[0] - Neutralino.storage.setData('config', JSON.stringify(config)) + config.serverFolder = folder[0] + Neutralino.storage.setData('config', JSON.stringify(config)) - displayServerFolder() - enableServerButton() + displayServerFolder() + enableServerButton() } /** * Launch the game with no modifications nor proxy */ async function launchOfficial() { - const config = await getCfg() + const config = await getCfg() - Neutralino.os.execCommand(`"${config.gameexe}"`) + Neutralino.os.execCommand(`"${config.gameexe}"`) } /** * Launch the game with a proxy */ async function launchPrivate() { - const ip = document.getElementById('ip').value || '127.0.0.1' - const port = document.getElementById('port').value || '443' + const ip = document.getElementById('ip').value || '127.0.0.1' + const port = document.getElementById('port').value || '443' - const config = await getCfg() + const config = await getCfg() - console.log('connecting to ' + ip + ':' + port) + console.log('connecting to ' + ip + ':' + port) - // Set the last connect - config.lastConnect = ip - Neutralino.storage.setData('config', JSON.stringify(config)) + // Set the last connect + config.lastConnect = ip + Neutralino.storage.setData('config', JSON.stringify(config)) - // Pass IP and game folder to the private server launcher - createCmdWindow(`.\\scripts\\private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gameexe}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) + // Pass IP and game folder to the private server launcher + createCmdWindow(`.\\scripts\\private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gameexe}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) } async function launchLocalServer() { - const config = await getCfg() + const config = await getCfg() - createCmdWindow(`.\\scripts\\local_server_launch.cmd "${config.serverFolder}"`).catch(e => console.log(e)) + createCmdWindow(`.\\scripts\\local_server_launch.cmd "${config.serverFolder}"`).catch(e => console.log(e)) } diff --git a/resources/js/login.js b/resources/js/login.js index 60188d7..87c0de9 100644 --- a/resources/js/login.js +++ b/resources/js/login.js @@ -2,153 +2,153 @@ * Toggle the login section */ async function setLoginSection() { - const title = document.getElementById('loginSectionTitle'); - const altTitle = document.getElementById('registerSectionTitle'); - const loginSection = document.getElementById('loginPopupContentBody'); - const registerSection = document.getElementById('registerPopupContentBody'); + const title = document.getElementById('loginSectionTitle') + const altTitle = document.getElementById('registerSectionTitle') + const loginSection = document.getElementById('loginPopupContentBody') + const registerSection = document.getElementById('registerPopupContentBody') - title.classList.add('selectedTitle') - altTitle.classList.remove('selectedTitle') + title.classList.add('selectedTitle') + altTitle.classList.remove('selectedTitle') - loginSection.style.removeProperty('display'); - registerSection.style.display = 'none'; + loginSection.style.removeProperty('display') + registerSection.style.display = 'none' } /** * Toggle the register section */ async function setRegisterSection(fromLogin = false) { - const title = document.getElementById('registerSectionTitle'); - const altTitle = document.getElementById('loginSectionTitle'); - const loginSection = document.getElementById('loginPopupContentBody'); - const registerSection = document.getElementById('registerPopupContentBody'); + const title = document.getElementById('registerSectionTitle') + const altTitle = document.getElementById('loginSectionTitle') + const loginSection = document.getElementById('loginPopupContentBody') + const registerSection = document.getElementById('registerPopupContentBody') - title.classList.add('selectedTitle') - altTitle.classList.remove('selectedTitle') + title.classList.add('selectedTitle') + altTitle.classList.remove('selectedTitle') - loginSection.style.display = 'none'; - registerSection.style.removeProperty('display'); + loginSection.style.display = 'none' + registerSection.style.removeProperty('display') - if (fromLogin) { + if (fromLogin) { // Take the values from the login section and put them in the register section - const loginUsername = document.getElementById('loginUsername').value; - const loginPassword = document.getElementById('loginPassword').value; + const loginUsername = document.getElementById('loginUsername').value + const loginPassword = document.getElementById('loginPassword').value - document.getElementById('registerUsername').value = loginUsername; - document.getElementById('registerPassword').value = loginPassword; - } + document.getElementById('registerUsername').value = loginUsername + document.getElementById('registerPassword').value = loginPassword + } } function parseJwt(token) { - const base64Url = token.split('.')[1]; - const base64 = base64Url.replace('-', '+').replace('_', '/'); - return JSON.parse(window.atob(base64)); + const base64Url = token.split('.')[1] + const base64 = base64Url.replace('-', '+').replace('_', '/') + return JSON.parse(window.atob(base64)) } /** * Attempt login and launch game */ async function login() { - const username = document.getElementById('loginUsername').value; - const password = document.getElementById('loginPassword').value; - const ip = document.getElementById('ip').value; - const port = document.getElementById('port').value || '443'; - const config = await getCfg(); - const useHttps = config.useHttps; - const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`; + const username = document.getElementById('loginUsername').value + const password = document.getElementById('loginPassword').value + const ip = document.getElementById('ip').value + const port = document.getElementById('port').value || '443' + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` - const reqBody = { - username, - password, - } + const reqBody = { + username, + password, + } - const { data } = await axios.post(url + '/authentication/login', reqBody) + const { data } = await axios.post(url + '/authentication/login', reqBody) - switch(data.message) { + switch(data.message) { case 'INVALID_ACCOUNT': - displayLoginAlert(localeObj.alertInvalid || 'Invalid username or password', 'error'); - break; + displayLoginAlert(localeObj.alertInvalid || 'Invalid username or password', 'error') + break case 'NO_PASSWORD': - // No account password, create one with change password - displayLoginAlert(localeObj.alertNoPass || 'No password set, please change password', 'warn'); - break; + // No account password, create one with change password + displayLoginAlert(localeObj.alertNoPass || 'No password set, please change password', 'warn') + break case 'UNKNOWN': - // Unknown error, contact server owner - displayLoginAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error'); - break; + // Unknown error, contact server owner + displayLoginAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') + break case undefined: case null: case 'AUTH_DISABLED': - // Authentication is disabled, we can just connect the user - displayLoginAlert(localeObj.alertAuthNoLogin || 'Authentication is disabled, no need to log in!', 'warn'); - launchPrivate(); - break; + // Authentication is disabled, we can just connect the user + displayLoginAlert(localeObj.alertAuthNoLogin || 'Authentication is disabled, no need to log in!', 'warn') + launchPrivate() + break default: - // Success! Copy the JWT token to their clipboard - const tkData = parseJwt(data.jwt) - await Neutralino.clipboard.writeText(tkData.token) + // Success! Copy the JWT token to their clipboard + const tkData = parseJwt(data.jwt) + await Neutralino.clipboard.writeText(tkData.token) - displayLoginAlert(localeObj.alertLoginSuccess || 'Login successful! Token copied to clipboard. Paste this token into the username field of the game to log in.', 'success', 8000); - launchPrivate() - break; - } + displayLoginAlert(localeObj.alertLoginSuccess || 'Login successful! Token copied to clipboard. Paste this token into the username field of the game to log in.', 'success', 8000) + launchPrivate() + break + } } /** * Attempt registration, do not launch game */ async function register() { - const username = document.getElementById('registerUsername').value; - const password = document.getElementById('registerPassword').value; - const password_confirmation = document.getElementById('registerPasswordConfirm').value; - const ip = document.getElementById('ip').value; - const port = document.getElementById('port').value || '443'; - const config = await getCfg(); - const useHttps = config.useHttps; - const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`; + const username = document.getElementById('registerUsername').value + const password = document.getElementById('registerPassword').value + const password_confirmation = document.getElementById('registerPasswordConfirm').value + const ip = document.getElementById('ip').value + const port = document.getElementById('port').value || '443' + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` - const reqBody = { - username, - password, - password_confirmation - } + const reqBody = { + username, + password, + password_confirmation + } - const { data } = await axios.post(url + '/authentication/register', reqBody) + const { data } = await axios.post(url + '/authentication/register', reqBody) - switch(data.message) { + switch(data.message) { case 'USERNAME_TAKEN': - // Username is taken - displayRegisterAlert(localeObj.alertUserTaken || 'Username is taken', 'error'); - break; + // Username is taken + displayRegisterAlert(localeObj.alertUserTaken || 'Username is taken', 'error') + break case 'PASSWORD_MISMATCH': - // The password and password confirmation do not match - displayRegisterAlert(localStorage.alertPassMismatch || 'Password and password confirmation do not match', 'error'); - break; + // The password and password confirmation do not match + displayRegisterAlert(localStorage.alertPassMismatch || 'Password and password confirmation do not match', 'error') + break case 'UNKNOWN': - // Unknown error, contact server owner - displayRegisterAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error'); - break; + // Unknown error, contact server owner + displayRegisterAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') + break case undefined: case null: case 'AUTH_DISABLED': - // Authentication is disabled, we can just connect the user - displayRegisterAlert(localeObj.alertAuthNoRegister || 'Authentication is disabled, no need to register!', 'warn'); - break; + // Authentication is disabled, we can just connect the user + displayRegisterAlert(localeObj.alertAuthNoRegister || 'Authentication is disabled, no need to register!', 'warn') + break default: - // Success!! Bring them to the login screen and auto-input their username - const loginUsername = document.getElementById('loginUsername'); - loginUsername.value = username; + // Success!! Bring them to the login screen and auto-input their username + const loginUsername = document.getElementById('loginUsername') + loginUsername.value = username - setLoginSection(); - displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000); - break; - } + setLoginSection() + displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000) + break + } } diff --git a/resources/js/onLoad.js b/resources/js/onLoad.js index bc96832..e1942c8 100644 --- a/resources/js/onLoad.js +++ b/resources/js/onLoad.js @@ -3,87 +3,87 @@ * Every autofill, such as backgrounds and the game folder, * should be done here to ensure DOM contents are loaded. */ - document.addEventListener('DOMContentLoaded', async () => { - displayUpdate(); - setBackgroundImage(); - displayGameFolder(); - displayServerFolder(); +document.addEventListener('DOMContentLoaded', async () => { + displayUpdate() + setBackgroundImage() + displayGameFolder() + displayServerFolder() - // Set title version - document.querySelector('#version').innerHTML = NL_APPVERSION + // Set title version + document.querySelector('#version').innerHTML = NL_APPVERSION - const config = await getCfg() - const ipArr = await getFavIps() + const config = await getCfg() + const ipArr = await getFavIps() - if (config.serverLaunchPanel) { - displayServerLaunchSection() - } - - // Set last connect - document.querySelector('#ip').value = config.lastConnect - - if (ipArr.includes(config.lastConnect)) { - document.querySelector('#star').src = 'icons/star_filled.svg' - } - - // Disable private game launch if proxy IP or proxy server is not found - const playPriv = document.querySelector('#playPrivate') - - if (!(await proxyIsInstalled())) { - playPriv.classList.add('disabled') - playPriv.disabled = true - } - - // Exit favorites list and settings panel when clicking outside of it - window.addEventListener("click", function(e) { - const favList = document.querySelector('#ipList') - const settingsPanel = document.querySelector('#settingsPanel') - const downloadPanel = document.querySelector('#downloadPanel') - - // This will close the favorites list no matter what is clicked - if (favList.style.display !== 'none') { - favList.style.display = 'none' - favList.style.transform = '' + if (config.serverLaunchPanel) { + displayServerLaunchSection() } - // This will close the settings panel no matter what is clicked - let checkElm = e.target + // Set last connect + document.querySelector('#ip').value = config.lastConnect - while(checkElm.tagName !== 'BODY') { - if (checkElm.id === 'settingsPanel' + if (ipArr.includes(config.lastConnect)) { + document.querySelector('#star').src = 'icons/star_filled.svg' + } + + // Disable private game launch if proxy IP or proxy server is not found + const playPriv = document.querySelector('#playPrivate') + + if (!(await proxyIsInstalled())) { + playPriv.classList.add('disabled') + playPriv.disabled = true + } + + // Exit favorites list and settings panel when clicking outside of it + window.addEventListener('click', function(e) { + const favList = document.querySelector('#ipList') + const settingsPanel = document.querySelector('#settingsPanel') + const downloadPanel = document.querySelector('#downloadPanel') + + // This will close the favorites list no matter what is clicked + if (favList.style.display !== 'none') { + favList.style.display = 'none' + favList.style.transform = '' + } + + // This will close the settings panel no matter what is clicked + let checkElm = e.target + + while(checkElm.tagName !== 'BODY') { + if (checkElm.id === 'settingsPanel' || checkElm.id === 'settingsBtn') { - return - } + return + } - if (checkElm.id === 'downloadPanel' || + if (checkElm.id === 'downloadPanel' || checkElm.id === 'downloadBtn') { - return - } + return + } - checkElm = checkElm.parentElement - } + checkElm = checkElm.parentElement + } - // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel - if (checkElm.tagName === 'BODY') { - // This will close the settings panel only when something outside of it is clicked - if (settingsPanel.style.display !== 'none') { - settingsPanel.style.display = 'none' - } + // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel + if (checkElm.tagName === 'BODY') { + // This will close the settings panel only when something outside of it is clicked + if (settingsPanel.style.display !== 'none') { + settingsPanel.style.display = 'none' + } - if (downloadPanel.style.display !== 'none') { - downloadPanel.style.display = 'none' - } - } - }); + if (downloadPanel.style.display !== 'none') { + downloadPanel.style.display = 'none' + } + } + }) - // Ensure we do the translation at the very end, after everything else has loaded - await doTranslation() + // Ensure we do the translation at the very end, after everything else has loaded + await doTranslation() - if (!config.gameexe) { - handleGameNotSet() - } + if (!config.gameexe) { + handleGameNotSet() + } - if (!config.serverFolder) { - handleServerNotSet() - } + if (!config.serverFolder) { + handleServerNotSet() + } }) diff --git a/resources/js/options.js b/resources/js/options.js index 58da7f6..a42f899 100644 --- a/resources/js/options.js +++ b/resources/js/options.js @@ -2,54 +2,54 @@ * Toggle the killswitch script */ async function toggleKillSwitch() { - const killSwitch = document.querySelector('#killswitchOption') - const config = await getCfg() + const killSwitch = document.querySelector('#killswitchOption') + const config = await getCfg() - config.enableKillswitch = killSwitch.checked + config.enableKillswitch = killSwitch.checked - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) } /** * Toggles the server launching panel */ async function toggleServerLaunchSection() { - const config = await getCfg() + const config = await getCfg() - displayServerLaunchSection() + displayServerLaunchSection() - // Save setting - config.serverLaunchPanel = !config.serverLaunchPanel - Neutralino.storage.setData('config', JSON.stringify(config)) + // Save setting + config.serverLaunchPanel = !config.serverLaunchPanel + Neutralino.storage.setData('config', JSON.stringify(config)) } /** * Get all languages for the language selector */ async function getLanguages() { - const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) - const config = await getCfg() + const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) + const config = await getCfg() - // Clear language options - const languageSelect = document.querySelector('#languageSelect') - languageSelect.innerHTML = '' + // Clear language options + const languageSelect = document.querySelector('#languageSelect') + languageSelect.innerHTML = '' - // Load all languages as options - for (const file of languageFiles) { - const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName - const lang = file.entry.split('.json')[0] + // Load all languages as options + for (const file of languageFiles) { + const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName + const lang = file.entry.split('.json')[0] - const option = document.createElement('option') - option.value = lang - option.innerHTML = fullLanguageName + const option = document.createElement('option') + option.value = lang + option.innerHTML = fullLanguageName - // Set language selected to config language - if (lang === config.language) { - option.selected = true - } + // Set language selected to config language + if (lang === config.language) { + option.selected = true + } - document.querySelector('#languageSelect').appendChild(option) - } + document.querySelector('#languageSelect').appendChild(option) + } } /** @@ -58,27 +58,27 @@ async function getLanguages() { * @param {DOMElement} elm */ async function handleLanguageChange(elm) { - const list = elm - const config = await getCfg() + const list = elm + const config = await getCfg() - // Set language in config - config.language = list.value - Neutralino.storage.setData('config', JSON.stringify(config)) + // Set language in config + config.language = list.value + Neutralino.storage.setData('config', JSON.stringify(config)) - // Force refresh of application, no need for restart! - window.location.reload() + // Force refresh of application, no need for restart! + window.location.reload() } /** * Toggle the use of HTTPS */ - async function toggleHttps() { - const httpsCheckbox = document.querySelector('#httpsOption') - const config = await getCfg() +async function toggleHttps() { + const httpsCheckbox = document.querySelector('#httpsOption') + const config = await getCfg() - config.useHttps = httpsCheckbox.checked + config.useHttps = httpsCheckbox.checked - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) } /** @@ -86,29 +86,29 @@ async function handleLanguageChange(elm) { * OR * Remove the current value of the IP input from the favorites list */ - async function setFavorite() { - const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value || '443' - const ipArr = await getFavIps() +async function setFavorite() { + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value || '443' + const ipArr = await getFavIps() - const addr = `${ip}:${port}` + const addr = `${ip}:${port}` - // Set star icon - const star = document.querySelector('#star') + // Set star icon + const star = document.querySelector('#star') - if (star.src.includes('filled') && ip) { - star.src = 'icons/star_empty.svg' + if (star.src.includes('filled') && ip) { + star.src = 'icons/star_empty.svg' - // remove from list - ipArr.splice(ipArr.indexOf(addr), 1) - } else { - star.src = 'icons/star_filled.svg' + // remove from list + ipArr.splice(ipArr.indexOf(addr), 1) + } else { + star.src = 'icons/star_filled.svg' - // add to list - if (ip && !ipArr.includes(addr)) { - ipArr.push(addr) + // add to list + if (ip && !ipArr.includes(addr)) { + ipArr.push(addr) + } } - } - Neutralino.storage.setData('favorites', JSON.stringify(ipArr)) + Neutralino.storage.setData('favorites', JSON.stringify(ipArr)) } diff --git a/resources/js/translation.js b/resources/js/translation.js index dd80b83..47f0eb0 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -1,110 +1,110 @@ async function doTranslation() { - const config = await getCfg() + const config = await getCfg() - // See if the localization file exists - const localizations = await filesystem.readDirectory(`${NL_CWD}/languages`) + // See if the localization file exists + const localizations = await filesystem.readDirectory(`${NL_CWD}/languages`) - // Use english if the selected file does not exist - const selectedLanguage = localizations.find(f => f.entry === `${config.language}.json`) + // Use english if the selected file does not exist + const selectedLanguage = localizations.find(f => f.entry === `${config.language}.json`) - // Use english if the selected file does not exist - if (!selectedLanguage) { - config.language = 'en' - } + // Use english if the selected file does not exist + if (!selectedLanguage) { + config.language = 'en' + } - const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`) - const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`) - engLocaleObj = JSON.parse(engLocale) - localeObj = JSON.parse(localization) + const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`) + const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`) + engLocaleObj = JSON.parse(engLocale) + localeObj = JSON.parse(localization) - const set = (id, localeString) => document.getElementById(id).innerText = localeObj[localeString] || engLocaleObj[localeString] + const set = (id, localeString) => document.getElementById(id).innerText = localeObj[localeString] || engLocaleObj[localeString] - // Begin filling in values - set('titleSection', 'appName') + // Begin filling in values + set('titleSection', 'appName') - const verSpan = document.createElement('span') - verSpan.id = 'version' - verSpan.innerHTML = ` v${NL_APPVERSION}` + const verSpan = document.createElement('span') + verSpan.id = 'version' + verSpan.innerHTML = ` v${NL_APPVERSION}` - document.querySelector('#titleSection').appendChild(verSpan) + document.querySelector('#titleSection').appendChild(verSpan) - // Play buttons - set('playOfficial', 'playOfficial') - set('playPrivate', 'playPrivate') - set('serverLaunch', 'launchLocalServer') + // Play buttons + set('playOfficial', 'playOfficial') + set('playPrivate', 'playPrivate') + set('serverLaunch', 'launchLocalServer') - // File select buttons - set('gameExeSet', 'gameExeSet') - set('grasscutterFileSet', 'grasscutterFileSet') + // File select buttons + set('gameExeSet', 'gameExeSet') + set('grasscutterFileSet', 'grasscutterFileSet') - // Private options - document.querySelector('#ip').placeholder = localeObj.ipPlaceholder - document.querySelector('#port').placeholder = localeObj.portPlaceholder + // Private options + document.querySelector('#ip').placeholder = localeObj.ipPlaceholder + document.querySelector('#port').placeholder = localeObj.portPlaceholder - // Settings - set('fullSettingsTitle', 'settingsTitle') - set('scriptsTitle', 'scriptsSectionTitle') - set('killswitchTitle', 'killswitchOption') - set('killswitchSubtitle', 'killswitchSubtitle') - set('proxyTitle', 'proxyOption') - set('proxyInstall', 'proxyInstallBtn') - set('proxySubtitle', 'proxySubtitle') - set('updateBtn', 'updateOption') - set('updateTitle', 'updateOption') - set('updateSubtitle', 'updateSubtitle') - set('languageTitle', 'languageOption') - set('languageSubtitle', 'languageSubtitle') - set('serverLaunchTitle', 'enableServerLauncherOption') - set('serverSubtitle', 'enableServerLauncherSubtitle') - set('httpsTitle', 'httpsOption') - set('httpsSubtitle', 'httpsSubtitle') + // Settings + set('fullSettingsTitle', 'settingsTitle') + set('scriptsTitle', 'scriptsSectionTitle') + set('killswitchTitle', 'killswitchOption') + set('killswitchSubtitle', 'killswitchSubtitle') + set('proxyTitle', 'proxyOption') + set('proxyInstall', 'proxyInstallBtn') + set('proxySubtitle', 'proxySubtitle') + set('updateBtn', 'updateOption') + set('updateTitle', 'updateOption') + set('updateSubtitle', 'updateSubtitle') + set('languageTitle', 'languageOption') + set('languageSubtitle', 'languageSubtitle') + set('serverLaunchTitle', 'enableServerLauncherOption') + set('serverSubtitle', 'enableServerLauncherSubtitle') + set('httpsTitle', 'httpsOption') + set('httpsSubtitle', 'httpsSubtitle') - // Intro popup - const popup = document.getElementById('firstTimeNotice') - const introSpan = popup.querySelector('span') - const boldIntroSpan = document.createElement('span') + // Intro popup + const popup = document.getElementById('firstTimeNotice') + const introSpan = popup.querySelector('span') + const boldIntroSpan = document.createElement('span') - boldIntroSpan.innerHTML = localeObj.introSen1 + '\n' - boldIntroSpan.classList.add('boldTitle') + boldIntroSpan.innerHTML = localeObj.introSen1 + '\n' + boldIntroSpan.classList.add('boldTitle') - introSpan.appendChild(boldIntroSpan) + introSpan.appendChild(boldIntroSpan) - introSpan.innerHTML += localeObj.introSen2 + '
' - introSpan.innerHTML += localeObj.introSen3 + '
' - introSpan.innerHTML += localeObj.introSen4 + '
' + introSpan.innerHTML += localeObj.introSen2 + '
' + introSpan.innerHTML += localeObj.introSen3 + '
' + introSpan.innerHTML += localeObj.introSen4 + '
' - set('firstTimeInstallBtn', 'proxyInstallBtn') - set('firstTimeDenyBtn', 'proxyInstallDeny') + set('firstTimeInstallBtn', 'proxyInstallBtn') + set('firstTimeDenyBtn', 'proxyInstallDeny') - // Login section - set('loginSectionTitle', 'authLoginTitle') - set('registerSectionTitle', 'authRegisterTitle') - set('loggingInToIndicator', 'loggingInTo') - set('registeringToIndicator', 'registeringFor') - set('loginUsernameIndicator', 'authUsername') - set('loginPasswordIndicator', 'authPassword') - set('registerUsernameIndicator', 'authUsername') - set('registerPasswordIndicator', 'authPassword') - set('registerConfirmIndicator', 'authConfirmPassword') - set('loginPopupContentBodyBtnLogin', 'authLoginBtn') - set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') - set('noLoginBtn', 'launchWithoutAuth') + // Login section + set('loginSectionTitle', 'authLoginTitle') + set('registerSectionTitle', 'authRegisterTitle') + set('loggingInToIndicator', 'loggingInTo') + set('registeringToIndicator', 'registeringFor') + set('loginUsernameIndicator', 'authUsername') + set('loginPasswordIndicator', 'authPassword') + set('registerUsernameIndicator', 'authUsername') + set('registerPasswordIndicator', 'authPassword') + set('registerConfirmIndicator', 'authConfirmPassword') + set('loginPopupContentBodyBtnLogin', 'authLoginBtn') + set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') + set('noLoginBtn', 'launchWithoutAuth') - // Downloads section - set('downloadTitle', 'downloadTitle') - set('grassclipperTitle', 'grassclipperTitle') - set('grasscutterTitle', 'grasscutterTitle') - set('installerTitle', 'installerTitle') - set('installerSubtitle', 'installerSubtitle') - set('downloadStable', 'downloadStable') - set('stableSubtitle', 'stableSubtitle') - set('downloadDev', 'downloadDev') - set('devSubtitle', 'downloadSubtitle') - set('downloadResources', 'downloadResources') - set('devSubtitle', 'devSubtitle') - set('stableInstall', 'stableInstall') - set('devInstall', 'devInstall') + // Downloads section + set('downloadTitle', 'downloadTitle') + set('grassclipperTitle', 'grassclipperTitle') + set('grasscutterTitle', 'grasscutterTitle') + set('installerTitle', 'installerTitle') + set('installerSubtitle', 'installerSubtitle') + set('downloadStable', 'downloadStable') + set('stableSubtitle', 'stableSubtitle') + set('downloadDev', 'downloadDev') + set('devSubtitle', 'downloadSubtitle') + set('downloadResources', 'downloadResources') + set('devSubtitle', 'devSubtitle') + set('stableInstall', 'stableInstall') + set('devInstall', 'devInstall') - // update notification - set('updateNotifText', 'updateNotifText') + // update notification + set('updateNotifText', 'updateNotifText') } \ No newline at end of file diff --git a/resources/js/windowDrag.js b/resources/js/windowDrag.js index b9aa3f5..e8d8704 100644 --- a/resources/js/windowDrag.js +++ b/resources/js/windowDrag.js @@ -1,25 +1,25 @@ // https://stackoverflow.com/questions/67971689/positioning-the-borderless-window-in-neutralino-js // had to use this since the in-built function breaks the close and minimize buttons -let dragging = false, ratio = 1, posX, posY; -let draggable; +let dragging = false, ratio = 1, posX, posY +let draggable document.addEventListener('DOMContentLoaded', async () => { - draggable = document.getElementById('controlBar'); + draggable = document.getElementById('controlBar') - // Listen to hovers - draggable.onmousedown = function (e) { - ratio = window.devicePixelRatio + // Listen to hovers + draggable.onmousedown = function (e) { + ratio = window.devicePixelRatio - posX = e.pageX * ratio, posY = e.pageY * ratio; - dragging = true; - } + posX = e.pageX * ratio, posY = e.pageY * ratio + dragging = true + } - // Patch for monitors with scaling enabled, allows them to detach from the titlebar anywhere - window.onmouseup = function (e) { - dragging = false; - } + // Patch for monitors with scaling enabled, allows them to detach from the titlebar anywhere + window.onmouseup = function (e) { + dragging = false + } - document.onmousemove = function (e) { - if (dragging) Neutralino.window.move(e.screenX * ratio - posX, e.screenY * ratio - posY); - } + document.onmousemove = function (e) { + if (dragging) Neutralino.window.move(e.screenX * ratio - posX, e.screenY * ratio - posY) + } }) \ No newline at end of file