This commit introduces support for Microsoft Authentication via the settings menu. There are a few known issues and TODOs which should not be hard to fix. Once the auth flow from the settings screen is complete, the auth folow for first-time login (ie no accounts added yet) must be added. Should not be very difficult. The plan is to add one more view with two login buttons. The Mojang button will just bring you to the login page. The microsoft one will launch OAuth2.
226 lines
6.8 KiB
JavaScript
226 lines
6.8 KiB
JavaScript
/**
|
|
* Script for login.ejs
|
|
*/
|
|
// Validation Regexes.
|
|
const validUsername = /^[a-zA-Z0-9_]{1,16}$/
|
|
const basicEmail = /^\S+@\S+\.\S+$/
|
|
//const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
|
|
|
|
// Login Elements
|
|
const loginCancelContainer = document.getElementById('loginCancelContainer')
|
|
const loginCancelButton = document.getElementById('loginCancelButton')
|
|
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')
|
|
const loginForm = document.getElementById('loginForm')
|
|
|
|
// Control variables.
|
|
let lu = false, lp = false
|
|
|
|
const loggerLogin = LoggerUtil('%c[Login]', 'color: #000668; font-weight: bold')
|
|
|
|
|
|
/**
|
|
* 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 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')
|
|
void element.offsetWidth
|
|
element.classList.add('shake')
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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)){
|
|
showError(loginEmailError, Lang.queryJS('login.error.invalidValue'))
|
|
loginDisabled(true)
|
|
lu = false
|
|
} else {
|
|
loginEmailError.style.opacity = 0
|
|
lu = true
|
|
if(lp){
|
|
loginDisabled(false)
|
|
}
|
|
}
|
|
} else {
|
|
lu = false
|
|
showError(loginEmailError, Lang.queryJS('login.error.requiredValue'))
|
|
loginDisabled(true)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate that the password field is not empty.
|
|
*
|
|
* @param {string} value The password value.
|
|
*/
|
|
function validatePassword(value){
|
|
if(value){
|
|
loginPasswordError.style.opacity = 0
|
|
lp = true
|
|
if(lu){
|
|
loginDisabled(false)
|
|
}
|
|
} else {
|
|
lp = false
|
|
showError(loginPasswordError, Lang.queryJS('login.error.invalidValue'))
|
|
loginDisabled(true)
|
|
}
|
|
}
|
|
|
|
// Emphasize errors with shake when focus is lost.
|
|
loginUsername.addEventListener('focusout', (e) => {
|
|
validateEmail(e.target.value)
|
|
shakeError(loginEmailError)
|
|
})
|
|
loginPassword.addEventListener('focusout', (e) => {
|
|
validatePassword(e.target.value)
|
|
shakeError(loginPasswordError)
|
|
})
|
|
|
|
// Validate input for each field.
|
|
loginUsername.addEventListener('input', (e) => {
|
|
validateEmail(e.target.value)
|
|
})
|
|
loginPassword.addEventListener('input', (e) => {
|
|
validatePassword(e.target.value)
|
|
})
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* @param {boolean} v True to enable, false to disable.
|
|
*/
|
|
function loginLoading(v){
|
|
if(v){
|
|
loginButton.setAttribute('loading', v)
|
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.login'), Lang.queryJS('login.loggingIn'))
|
|
} else {
|
|
loginButton.removeAttribute('loading')
|
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.login'))
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enable or disable login form.
|
|
*
|
|
* @param {boolean} v True to enable, false to disable.
|
|
*/
|
|
function formDisabled(v){
|
|
loginDisabled(v)
|
|
loginCancelButton.disabled = v
|
|
loginUsername.disabled = v
|
|
loginPassword.disabled = v
|
|
if(v){
|
|
checkmarkContainer.setAttribute('disabled', v)
|
|
} else {
|
|
checkmarkContainer.removeAttribute('disabled')
|
|
}
|
|
loginRememberOption.disabled = v
|
|
}
|
|
|
|
let loginViewOnSuccess = VIEWS.landing
|
|
let loginViewOnCancel = VIEWS.settings
|
|
let loginViewCancelHandler
|
|
|
|
function loginCancelEnabled(val){
|
|
if(val){
|
|
$(loginCancelContainer).show()
|
|
} else {
|
|
$(loginCancelContainer).hide()
|
|
}
|
|
}
|
|
|
|
loginCancelButton.onclick = (e) => {
|
|
switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => {
|
|
loginUsername.value = ''
|
|
loginPassword.value = ''
|
|
loginCancelEnabled(false)
|
|
if(loginViewCancelHandler != null){
|
|
loginViewCancelHandler()
|
|
loginViewCancelHandler = null
|
|
}
|
|
})
|
|
}
|
|
|
|
// Disable default form behavior.
|
|
loginForm.onsubmit = () => { return false }
|
|
|
|
// Bind login button behavior.
|
|
loginButton.addEventListener('click', () => {
|
|
// Disable form.
|
|
formDisabled(true)
|
|
|
|
// Show loading stuff.
|
|
loginLoading(true)
|
|
|
|
AuthManager.addMojangAccount(loginUsername.value, loginPassword.value).then((value) => {
|
|
updateSelectedAccount(value)
|
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
|
$('.circle-loader').toggleClass('load-complete')
|
|
$('.checkmark').toggle()
|
|
setTimeout(() => {
|
|
switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => {
|
|
// Temporary workaround
|
|
if(loginViewOnSuccess === VIEWS.settings){
|
|
prepareSettings()
|
|
}
|
|
loginViewOnSuccess = VIEWS.landing // Reset this for good measure.
|
|
loginCancelEnabled(false) // Reset this for good measure.
|
|
loginViewCancelHandler = null // Reset this for good measure.
|
|
loginUsername.value = ''
|
|
loginPassword.value = ''
|
|
$('.circle-loader').toggleClass('load-complete')
|
|
$('.checkmark').toggle()
|
|
loginLoading(false)
|
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login'))
|
|
formDisabled(false)
|
|
})
|
|
}, 1000)
|
|
}).catch((displayableError) => {
|
|
loginLoading(false)
|
|
setOverlayContent(displayableError.title, displayableError.desc, Lang.queryJS('login.tryAgain'))
|
|
setOverlayHandler(() => {
|
|
formDisabled(false)
|
|
toggleOverlay(false)
|
|
})
|
|
toggleOverlay(true)
|
|
loggerLogin.log('Error while logging in.', displayableError)
|
|
})
|
|
|
|
}) |