diff --git a/app/assets/js/scripts/actionbinder.js b/app/assets/js/scripts/actionbinder.js index 10774bb3..ff7d779f 100644 --- a/app/assets/js/scripts/actionbinder.js +++ b/app/assets/js/scripts/actionbinder.js @@ -1,19 +1,6 @@ -const cp = require('child_process') -const path = require('path') -const {AssetGuard} = require(path.join(__dirname, 'assets', 'js', 'assetguard.js')) -const ProcessBuilder = require(path.join(__dirname, 'assets', 'js', 'processbuilder.js')) +// Requirements +const path = require('path') const ConfigManager = require(path.join(__dirname, 'assets', 'js', 'configmanager.js')) -const DiscordWrapper = require(path.join(__dirname, 'assets', 'js', 'discordwrapper.js')) -const Mojang = require(path.join(__dirname, 'assets', 'js', 'mojang.js')) -const AuthManager = require(path.join(__dirname, 'assets', 'js', 'authmanager.js')) -const ServerStatus = require(path.join(__dirname, 'assets', 'js', 'serverstatus.js')) -const {URL} = require('url') - -let mojangStatusListener -let serverStatusListener - -// Launch Elements -let launch_content, launch_details, launch_progress, launch_progress_label, launch_details_text // Synchronous Listener document.addEventListener('readystatechange', function(){ @@ -27,98 +14,7 @@ document.addEventListener('readystatechange', function(){ } if (document.readyState === 'interactive'){ - - // Save a reference to the launch elements. - launch_content = document.getElementById('launch_content') - launch_details = document.getElementById('launch_details') - launch_progress = document.getElementById('launch_progress') - launch_progress_label = document.getElementById('launch_progress_label') - launch_details_text = document.getElementById('launch_details_text') - - // Bind launch button - document.getElementById('launch_button').addEventListener('click', function(e){ - console.log('Launching game..') - const jExe = ConfigManager.getJavaExecutable() - if(jExe == null){ - asyncSystemScan() - } else { - - setLaunchDetails('Please wait..') - toggleLaunchArea(true) - setLaunchPercentage(0, 100) - - AssetGuard._validateJavaBinary(jExe).then((v) => { - if(v){ - dlAsync() - } else { - asyncSystemScan() - } - }) - } - }) - - // TODO convert this to dropdown menu. - // Bind selected server - document.getElementById('server_selection').innerHTML = '\u2022 ' + AssetGuard.getServerById(ConfigManager.getGameDirectory(), ConfigManager.getSelectedServer()).name - - - // Update Mojang Status Color - const refreshMojangStatuses = async function(){ - console.log('Refreshing Mojang Statuses..') - let status = 'grey' - try { - const statuses = await Mojang.status() - greenCount = 0 - for(let i=0; i { - if(m.content === 'validateJava'){ - - if(m.result == null){ - // If the result is null, no valid Java installation was found. - // Show this information to the user. - setOverlayContent( - 'No Compatible
Java Installation Found', - 'In order to join WesterosCraft, you need a 64-bit installation of Java 8. Would you like us to install a copy? By installing, you accept Oracle\'s license agreement.', - 'Install Java', - 'Install Manually' - ) - setOverlayHandler(() => { - setLaunchDetails('Preparing Java Download..') - sysAEx.send({task: 0, content: '_enqueueOracleJRE', argsArr: [ConfigManager.getLauncherDirectory()]}) - toggleOverlay(false) - }) - setDismissHandler(() => { - $('#overlayContent').fadeOut(250, () => { - //$('#overlayDismiss').toggle(false) - setOverlayContent( - 'Don\'t Forget!
Java is Required', - 'A valid x64 installation of Java 8 is required to launch. Downloads can be found on Oracle\'s website. Once installed, you will be able to connect to the server.

Please refer to our Troubleshooting Guide if you have any difficulty.', - 'I Understand', - 'Go Back' - ) - setOverlayHandler(() => { - toggleLaunchArea(false) - toggleOverlay(false) - }) - setDismissHandler(() => { - toggleOverlay(false, true) - asyncSystemScan() - }) - $('#overlayContent').fadeIn(250) - }) - }) - toggleOverlay(true, true) - - // TODO Add option to not install Java x64. - - } else { - // Java installation found, use this to launch the game. - ConfigManager.setJavaExecutable(m.result) - ConfigManager.save() - if(launchAfter){ - dlAsync() - } - sysAEx.disconnect() - } - - } else if(m.content === '_enqueueOracleJRE'){ - - if(m.result === true){ - - // Oracle JRE enqueued successfully, begin download. - setLaunchDetails('Downloading Java..') - sysAEx.send({task: 0, content: 'processDlQueues', argsArr: [[{id:'java', limit:1}]]}) - - } else { - - // Oracle JRE enqueue failed. Probably due to a change in their website format. - // User will have to follow the guide to install Java. - setOverlayContent( - 'Unexpected Issue:
Java Download Failed', - 'Unfortunately we\'ve encountered an issue while attempting to install Java. You will need to manually install a copy. Please check out our Troubleshooting Guide for more details and instructions.', - 'I Understand' - ) - setOverlayHandler(() => { - toggleOverlay(false) - toggleLaunchArea(false) - }) - toggleOverlay(true) - sysAEx.disconnect() - - } - - } else if(m.content === 'dl'){ - - if(m.task === 0){ - // Downloading.. - setDownloadPercentage(m.value, m.total, m.percent) - } else if(m.task === 1){ - // Download will be at 100%, remove the loading from the OS progress bar. - remote.getCurrentWindow().setProgressBar(-1) - - // Wait for extration to complete. - setLaunchDetails('Extracting..') - - } else if(m.task === 2){ - - // Extraction completed successfully. - ConfigManager.setJavaExecutable(m.jPath) - ConfigManager.save() - - setLaunchDetails('Java Installed!') - - if(launchAfter){ - dlAsync() - } - - sysAEx.disconnect() - } else { - console.error('Unknown download data type.', m) - } - } - }) - - // Begin system Java scan. - setLaunchDetails('Checking system info..') - sysAEx.send({task: 0, content: 'validateJava', argsArr: [ConfigManager.getLauncherDirectory()]}) - -} - -// Keep reference to Minecraft Process -let proc -// Is DiscordRPC enabled -let hasRPC = false -// Joined server regex -const servJoined = /[[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\] \[Client thread\/INFO\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/g -const gameJoined = /\[[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\] \[Client thread\/WARN\]: Skipping bad option: lastServer:/g -const gameJoined2 = /\[[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\] \[Client thread\/INFO\]: Created: \d+x\d+ textures-atlas/g - -let aEx -let serv -let versionData -let forgeData - -function dlAsync(login = true){ - - // Login parameter is temporary for debug purposes. Allows testing the validation/downloads without - // launching the game. - - if(login) { - if(ConfigManager.getSelectedAccount() == null){ - console.error('login first.') - //in devtools AuthManager.addAccount(username, pass) - return - } - } - - setLaunchDetails('Please wait..') - toggleLaunchArea(true) - setLaunchPercentage(0, 100) - - // Start AssetExec to run validations and downloads in a forked process. - aEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [ - ConfigManager.getGameDirectory(), - ConfigManager.getJavaExecutable() - ]) - - // Establish communications between the AssetExec and current process. - aEx.on('message', (m) => { - if(m.content === 'validateDistribution'){ - - setLaunchPercentage(20, 100) - serv = m.result - console.log('Forge Validation Complete.') - - // Begin version load. - setLaunchDetails('Loading version information..') - aEx.send({task: 0, content: 'loadVersionData', argsArr: [serv.mc_version]}) - - } else if(m.content === 'loadVersionData'){ - - setLaunchPercentage(40, 100) - versionData = m.result - console.log('Version data loaded.') - - // Begin asset validation. - setLaunchDetails('Validating asset integrity..') - aEx.send({task: 0, content: 'validateAssets', argsArr: [versionData]}) - - } else if(m.content === 'validateAssets'){ - - // Asset validation can *potentially* take longer, so let's track progress. - if(m.task === 0){ - const perc = (m.value/m.total)*20 - setLaunchPercentage(40+perc, 100, parseInt(40+perc)) - } else { - setLaunchPercentage(60, 100) - console.log('Asset Validation Complete') - - // Begin library validation. - setLaunchDetails('Validating library integrity..') - aEx.send({task: 0, content: 'validateLibraries', argsArr: [versionData]}) - } - - } else if(m.content === 'validateLibraries'){ - - setLaunchPercentage(80, 100) - console.log('Library validation complete.') - - // Begin miscellaneous validation. - setLaunchDetails('Validating miscellaneous file integrity..') - aEx.send({task: 0, content: 'validateMiscellaneous', argsArr: [versionData]}) - - } else if(m.content === 'validateMiscellaneous'){ - - setLaunchPercentage(100, 100) - console.log('File validation complete.') - - // Download queued files. - setLaunchDetails('Downloading files..') - aEx.send({task: 0, content: 'processDlQueues'}) - - } else if(m.content === 'dl'){ - - if(m.task === 0){ - - setDownloadPercentage(m.value, m.total, m.percent) - - } else if(m.task === 1){ - - // Download will be at 100%, remove the loading from the OS progress bar. - remote.getCurrentWindow().setProgressBar(-1) - - setLaunchDetails('Preparing to launch..') - aEx.send({task: 0, content: 'loadForgeData', argsArr: [serv.id]}) - - } else { - - console.error('Unknown download data type.', m) - - } - - } else if(m.content === 'loadForgeData'){ - - forgeData = m.result - - if(login) { - //if(!(await AuthManager.validateSelected())){ - // - //} - const authUser = ConfigManager.getSelectedAccount() - console.log('authu', authUser) - let pb = new ProcessBuilder(ConfigManager.getGameDirectory(), serv, versionData, forgeData, authUser) - setLaunchDetails('Launching game..') - try { - // Build Minecraft process. - proc = pb.build() - setLaunchDetails('Done. Enjoy the server!') - - // Attach a temporary listener to the client output. - // Will wait for a certain bit of text meaning that - // the client application has started, and we can hide - // the progress bar stuff. - const tempListener = function(data){ - if(data.indexOf('[Client thread/INFO]: -- System Details --') > -1){ - toggleLaunchArea(false) - if(hasRPC){ - DiscordWrapper.updateDetails('Loading game..') - } - proc.stdout.removeListener('data', tempListener) - } - } - - // Listener for Discord RPC. - const gameStateChange = function(data){ - if(servJoined.test(data)){ - DiscordWrapper.updateDetails('Exploring the Realm!') - } else if(gameJoined.test(data)){ - DiscordWrapper.updateDetails('Idling on Main Menu') - } - } - - // Bind listeners to stdout. - proc.stdout.on('data', tempListener) - proc.stdout.on('data', gameStateChange) - - // Init Discord Hook - const distro = AssetGuard.retrieveDistributionDataSync(ConfigManager.getGameDirectory) - if(distro.discord != null && serv.discord != null){ - DiscordWrapper.initRPC(distro.discord, serv.discord) - hasRPC = true - proc.on('close', (code, signal) => { - console.log('Shutting down Discord Rich Presence..') - DiscordWrapper.shutdownRPC() - hasRPC = false - proc = null - }) - } - - } catch(err) { - - // Show that there was an error then hide the - // progress area. Maybe switch this to an error - // alert in the future. TODO - setLaunchDetails('Error: See log for details..') - console.log(err) - setTimeout(function(){ - toggleLaunchArea(false) - }, 5000) - - } - } - - // Disconnect from AssetExec - aEx.disconnect() - - } - }) - - // Begin Validations - - // Validate Forge files. - setLaunchDetails('Loading server information..') - aEx.send({task: 0, content: 'validateDistribution', argsArr: [ConfigManager.getSelectedServer()]}) -} \ No newline at end of file diff --git a/app/assets/js/scripts/landing.js b/app/assets/js/scripts/landing.js new file mode 100644 index 00000000..a777b655 --- /dev/null +++ b/app/assets/js/scripts/landing.js @@ -0,0 +1,428 @@ +// Requirements +const cp = require('child_process') +const {URL} = require('url') + +// Internal Requirements +const {AssetGuard} = require(path.join(__dirname, 'assets', 'js', 'assetguard.js')) +const AuthManager = require(path.join(__dirname, 'assets', 'js', 'authmanager.js')) +const DiscordWrapper = require(path.join(__dirname, 'assets', 'js', 'discordwrapper.js')) +const Mojang = require(path.join(__dirname, 'assets', 'js', 'mojang.js')) +const ProcessBuilder = require(path.join(__dirname, 'assets', 'js', 'processbuilder.js')) +const ServerStatus = require(path.join(__dirname, 'assets', 'js', 'serverstatus.js')) + +// Launch Elements +const launch_content = document.getElementById('launch_content') +const launch_details = document.getElementById('launch_details') +const launch_progress = document.getElementById('launch_progress') +const launch_progress_label = document.getElementById('launch_progress_label') +const launch_details_text = document.getElementById('launch_details_text') + +// Bind launch button +document.getElementById('launch_button').addEventListener('click', function(e){ + console.log('Launching game..') + const jExe = ConfigManager.getJavaExecutable() + if(jExe == null){ + asyncSystemScan() + } else { + + setLaunchDetails('Please wait..') + toggleLaunchArea(true) + setLaunchPercentage(0, 100) + + AssetGuard._validateJavaBinary(jExe).then((v) => { + if(v){ + dlAsync() + } else { + asyncSystemScan() + } + }) + } +}) + +// TODO convert this to dropdown menu. +// Bind selected server +document.getElementById('server_selection').innerHTML = '\u2022 ' + AssetGuard.getServerById(ConfigManager.getGameDirectory(), ConfigManager.getSelectedServer()).name + +// Update Mojang Status Color +const refreshMojangStatuses = async function(){ + console.log('Refreshing Mojang Statuses..') + let status = 'grey' + try { + const statuses = await Mojang.status() + greenCount = 0 + for(let i=0; i { + if(m.content === 'validateJava'){ + + if(m.result == null){ + // If the result is null, no valid Java installation was found. + // Show this information to the user. + setOverlayContent( + 'No Compatible
Java Installation Found', + 'In order to join WesterosCraft, you need a 64-bit installation of Java 8. Would you like us to install a copy? By installing, you accept Oracle\'s license agreement.', + 'Install Java', + 'Install Manually' + ) + setOverlayHandler(() => { + setLaunchDetails('Preparing Java Download..') + sysAEx.send({task: 0, content: '_enqueueOracleJRE', argsArr: [ConfigManager.getLauncherDirectory()]}) + toggleOverlay(false) + }) + setDismissHandler(() => { + $('#overlayContent').fadeOut(250, () => { + //$('#overlayDismiss').toggle(false) + setOverlayContent( + 'Don\'t Forget!
Java is Required', + 'A valid x64 installation of Java 8 is required to launch. Downloads can be found on Oracle\'s website. Once installed, you will be able to connect to the server.

Please refer to our Troubleshooting Guide if you have any difficulty.', + 'I Understand', + 'Go Back' + ) + setOverlayHandler(() => { + toggleLaunchArea(false) + toggleOverlay(false) + }) + setDismissHandler(() => { + toggleOverlay(false, true) + asyncSystemScan() + }) + $('#overlayContent').fadeIn(250) + }) + }) + toggleOverlay(true, true) + + // TODO Add option to not install Java x64. + + } else { + // Java installation found, use this to launch the game. + ConfigManager.setJavaExecutable(m.result) + ConfigManager.save() + if(launchAfter){ + dlAsync() + } + sysAEx.disconnect() + } + + } else if(m.content === '_enqueueOracleJRE'){ + + if(m.result === true){ + + // Oracle JRE enqueued successfully, begin download. + setLaunchDetails('Downloading Java..') + sysAEx.send({task: 0, content: 'processDlQueues', argsArr: [[{id:'java', limit:1}]]}) + + } else { + + // Oracle JRE enqueue failed. Probably due to a change in their website format. + // User will have to follow the guide to install Java. + setOverlayContent( + 'Unexpected Issue:
Java Download Failed', + 'Unfortunately we\'ve encountered an issue while attempting to install Java. You will need to manually install a copy. Please check out our Troubleshooting Guide for more details and instructions.', + 'I Understand' + ) + setOverlayHandler(() => { + toggleOverlay(false) + toggleLaunchArea(false) + }) + toggleOverlay(true) + sysAEx.disconnect() + + } + + } else if(m.content === 'dl'){ + + if(m.task === 0){ + // Downloading.. + setDownloadPercentage(m.value, m.total, m.percent) + } else if(m.task === 1){ + // Download will be at 100%, remove the loading from the OS progress bar. + remote.getCurrentWindow().setProgressBar(-1) + + // Wait for extration to complete. + setLaunchDetails('Extracting..') + + } else if(m.task === 2){ + + // Extraction completed successfully. + ConfigManager.setJavaExecutable(m.jPath) + ConfigManager.save() + + setLaunchDetails('Java Installed!') + + if(launchAfter){ + dlAsync() + } + + sysAEx.disconnect() + } else { + console.error('Unknown download data type.', m) + } + } + }) + + // Begin system Java scan. + setLaunchDetails('Checking system info..') + sysAEx.send({task: 0, content: 'validateJava', argsArr: [ConfigManager.getLauncherDirectory()]}) + +} + +// Keep reference to Minecraft Process +let proc +// Is DiscordRPC enabled +let hasRPC = false +// Joined server regex +const servJoined = /[[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\] \[Client thread\/INFO\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/g +const gameJoined = /\[[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\] \[Client thread\/WARN\]: Skipping bad option: lastServer:/g +const gameJoined2 = /\[[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\] \[Client thread\/INFO\]: Created: \d+x\d+ textures-atlas/g + +let aEx +let serv +let versionData +let forgeData + +function dlAsync(login = true){ + + // Login parameter is temporary for debug purposes. Allows testing the validation/downloads without + // launching the game. + + if(login) { + if(ConfigManager.getSelectedAccount() == null){ + console.error('login first.') + //in devtools AuthManager.addAccount(username, pass) + return + } + } + + setLaunchDetails('Please wait..') + toggleLaunchArea(true) + setLaunchPercentage(0, 100) + + // Start AssetExec to run validations and downloads in a forked process. + aEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [ + ConfigManager.getGameDirectory(), + ConfigManager.getJavaExecutable() + ]) + + // Establish communications between the AssetExec and current process. + aEx.on('message', (m) => { + if(m.content === 'validateDistribution'){ + + setLaunchPercentage(20, 100) + serv = m.result + console.log('Forge Validation Complete.') + + // Begin version load. + setLaunchDetails('Loading version information..') + aEx.send({task: 0, content: 'loadVersionData', argsArr: [serv.mc_version]}) + + } else if(m.content === 'loadVersionData'){ + + setLaunchPercentage(40, 100) + versionData = m.result + console.log('Version data loaded.') + + // Begin asset validation. + setLaunchDetails('Validating asset integrity..') + aEx.send({task: 0, content: 'validateAssets', argsArr: [versionData]}) + + } else if(m.content === 'validateAssets'){ + + // Asset validation can *potentially* take longer, so let's track progress. + if(m.task === 0){ + const perc = (m.value/m.total)*20 + setLaunchPercentage(40+perc, 100, parseInt(40+perc)) + } else { + setLaunchPercentage(60, 100) + console.log('Asset Validation Complete') + + // Begin library validation. + setLaunchDetails('Validating library integrity..') + aEx.send({task: 0, content: 'validateLibraries', argsArr: [versionData]}) + } + + } else if(m.content === 'validateLibraries'){ + + setLaunchPercentage(80, 100) + console.log('Library validation complete.') + + // Begin miscellaneous validation. + setLaunchDetails('Validating miscellaneous file integrity..') + aEx.send({task: 0, content: 'validateMiscellaneous', argsArr: [versionData]}) + + } else if(m.content === 'validateMiscellaneous'){ + + setLaunchPercentage(100, 100) + console.log('File validation complete.') + + // Download queued files. + setLaunchDetails('Downloading files..') + aEx.send({task: 0, content: 'processDlQueues'}) + + } else if(m.content === 'dl'){ + + if(m.task === 0){ + + setDownloadPercentage(m.value, m.total, m.percent) + + } else if(m.task === 1){ + + // Download will be at 100%, remove the loading from the OS progress bar. + remote.getCurrentWindow().setProgressBar(-1) + + setLaunchDetails('Preparing to launch..') + aEx.send({task: 0, content: 'loadForgeData', argsArr: [serv.id]}) + + } else { + + console.error('Unknown download data type.', m) + + } + + } else if(m.content === 'loadForgeData'){ + + forgeData = m.result + + if(login) { + //if(!(await AuthManager.validateSelected())){ + // + //} + const authUser = ConfigManager.getSelectedAccount() + console.log('authu', authUser) + let pb = new ProcessBuilder(ConfigManager.getGameDirectory(), serv, versionData, forgeData, authUser) + setLaunchDetails('Launching game..') + try { + // Build Minecraft process. + proc = pb.build() + setLaunchDetails('Done. Enjoy the server!') + + // Attach a temporary listener to the client output. + // Will wait for a certain bit of text meaning that + // the client application has started, and we can hide + // the progress bar stuff. + const tempListener = function(data){ + if(data.indexOf('[Client thread/INFO]: -- System Details --') > -1){ + toggleLaunchArea(false) + if(hasRPC){ + DiscordWrapper.updateDetails('Loading game..') + } + proc.stdout.removeListener('data', tempListener) + } + } + + // Listener for Discord RPC. + const gameStateChange = function(data){ + if(servJoined.test(data)){ + DiscordWrapper.updateDetails('Exploring the Realm!') + } else if(gameJoined.test(data)){ + DiscordWrapper.updateDetails('Idling on Main Menu') + } + } + + // Bind listeners to stdout. + proc.stdout.on('data', tempListener) + proc.stdout.on('data', gameStateChange) + + // Init Discord Hook + const distro = AssetGuard.retrieveDistributionDataSync(ConfigManager.getGameDirectory) + if(distro.discord != null && serv.discord != null){ + DiscordWrapper.initRPC(distro.discord, serv.discord) + hasRPC = true + proc.on('close', (code, signal) => { + console.log('Shutting down Discord Rich Presence..') + DiscordWrapper.shutdownRPC() + hasRPC = false + proc = null + }) + } + + } catch(err) { + + // Show that there was an error then hide the + // progress area. Maybe switch this to an error + // alert in the future. TODO + setLaunchDetails('Error: See log for details..') + console.log(err) + setTimeout(function(){ + toggleLaunchArea(false) + }, 5000) + + } + } + + // Disconnect from AssetExec + aEx.disconnect() + + } + }) + + // Begin Validations + + // Validate Forge files. + setLaunchDetails('Loading server information..') + aEx.send({task: 0, content: 'validateDistribution', argsArr: [ConfigManager.getSelectedServer()]}) +} \ No newline at end of file diff --git a/app/assets/js/scripts/login.js b/app/assets/js/scripts/login.js index 5716a1ef..bca00769 100644 --- a/app/assets/js/scripts/login.js +++ b/app/assets/js/scripts/login.js @@ -1,33 +1,38 @@ //const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i // Validation Regexes. -const validUsername = /^[a-zA-Z0-9_]{1,16}$/ -const basicEmail = /^\S+@\S+\.\S+$/ +const validUsername = /^[a-zA-Z0-9_]{1,16}$/ +const basicEmail = /^\S+@\S+\.\S+$/ -// DOM cache. -const loginContainer = document.getElementById('loginContainer') -const loginErrorTitle = document.getElementById('loginErrorTitle') -const loginErrorDesc = document.getElementById('loginErrorDesc') -const loginErrorAcknowledge = document.getElementById('loginErrorAcknowledge') - -const loginEmailError = document.getElementById('loginEmailError') -const loginUsername = document.getElementById('loginUsername') -const loginPasswordError = document.getElementById('loginPasswordError') -const loginPassword = document.getElementById('loginPassword') -const checkmarkContainer = document.getElementById('checkmarkContainer') -const loginRememberOption = document.getElementById('loginRememberOption') -const loginButton = document.getElementById('loginButton') +// Login Elements +const loginEmailError = document.getElementById('loginEmailError') +const loginUsername = document.getElementById('loginUsername') +const loginPasswordError = document.getElementById('loginPasswordError') +const loginPassword = document.getElementById('loginPassword') +const checkmarkContainer = document.getElementById('checkmarkContainer') +const loginRememberOption = document.getElementById('loginRememberOption') +const loginButton = document.getElementById('loginButton') // Control variables. let lu = false, lp = false -// Show error element. + +/** + * Show a login error. + * + * @param {HTMLElement} element The element on which to display the error. + * @param {string} value The error text. + */ function showError(element, value){ element.innerHTML = value element.style.opacity = 1 } -// Shake error element. +/** + * Shake a login error to add emphasis. + * + * @param {HTMLElement} element The element to shake. + */ function shakeError(element){ if(element.style.opacity == 1){ element.classList.remove('shake') @@ -36,7 +41,11 @@ function shakeError(element){ } } -// Validate email field is neither empty nor invalid. +/** + * Validate that an email field is neither empty nor invalid. + * + * @param {string} value The email value. + */ function validateEmail(value){ if(value){ if(!basicEmail.test(value) && !validUsername.test(value)){ @@ -57,7 +66,11 @@ function validateEmail(value){ } } -// Validate password field is not empty. +/** + * Validate that the password field is not empty. + * + * @param {string} value The password value. + */ function validatePassword(value){ if(value){ loginPasswordError.style.opacity = 0 @@ -90,14 +103,22 @@ loginPassword.addEventListener('input', (e) => { validatePassword(e.target.value) }) -// Enable or disable login button. +/** + * Enable or disable the login button. + * + * @param {boolean} v True to enable, false to disable. + */ function loginDisabled(v){ if(loginButton.disabled !== v){ loginButton.disabled = v } } -// Enable or disable loading elements. +/** + * Enable or disable loading elements. + * + * @param {boolean} v True to enable, false to disable. + */ function loginLoading(v){ if(v){ loginButton.setAttribute('loading', v) @@ -108,7 +129,11 @@ function loginLoading(v){ } } -// Disable or enable login form. +/** + * Enable or disable login form. + * + * @param {boolean} v True to enable, false to disable. + */ function formDisabled(v){ loginDisabled(v) loginUsername.disabled = v @@ -121,6 +146,13 @@ function formDisabled(v){ loginRememberOption.disabled = v } +/** + * Parses an error and returns a user-friendly title and description + * for our error overlay. + * + * @param {Error | {cause: string, error: string, errorMessage: string}} err A Node.js + * error or Mojang error response. + */ function resolveError(err){ // Mojang Response => err.cause | err.error | err.errorMessage // Node error => err.code | err.message @@ -180,6 +212,7 @@ function resolveError(err){ } } +// Bind login button behavior. loginButton.addEventListener('click', () => { // Disable form. formDisabled(true) diff --git a/app/assets/js/scripts/uicore.js b/app/assets/js/scripts/uicore.js index 1ee20888..c2812e2b 100644 --- a/app/assets/js/scripts/uicore.js +++ b/app/assets/js/scripts/uicore.js @@ -4,7 +4,8 @@ * actions in this file should not require the usage of any internal * modules, excluding dependencies. */ -const $ = require('jquery'); +// Requirements +const $ = require('jquery'); const {remote, shell, webFrame} = require('electron') // Disable zoom, needed for darwin. diff --git a/app/landing.ejs b/app/landing.ejs index e896d437..40be735d 100644 --- a/app/landing.ejs +++ b/app/landing.ejs @@ -141,4 +141,5 @@ + \ No newline at end of file