eslint changes

This commit is contained in:
SpikeHD 2022-05-02 22:44:57 -07:00
parent f0210cdbfe
commit eae6cc087b
12 changed files with 818 additions and 786 deletions

29
.eslintrc.json Normal file
View File

@ -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"
]
}
}

View File

@ -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"
}
}

View File

@ -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)
}

View File

@ -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()
}

View File

@ -3,28 +3,28 @@
*
* @returns {Promise<string>}
*/
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<string[]>}
*/
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()
}

View File

@ -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')
})
})

View File

@ -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))
}

View File

@ -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
}
}

View File

@ -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()
}
})

View File

@ -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))
}

View File

@ -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 + '<br>'
introSpan.innerHTML += localeObj.introSen3 + '<br>'
introSpan.innerHTML += localeObj.introSen4 + '<br>'
introSpan.innerHTML += localeObj.introSen2 + '<br>'
introSpan.innerHTML += localeObj.introSen3 + '<br>'
introSpan.innerHTML += localeObj.introSen4 + '<br>'
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')
}

View File

@ -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)
}
})