class Account{ constructor(touchEnabled){ this.touchEnabled = touchEnabled cancelTouch = false this.locked = false if(account.loggedIn){ this.accountForm() }else{ this.loginForm() } this.selected = this.items.length - 1 this.keyboard = new Keyboard({ confirm: ["enter", "space", "don_l", "don_r"], previous: ["left", "up", "ka_l"], next: ["right", "down", "ka_r"], back: ["escape"] }, this.keyPressed.bind(this)) this.gamepad = new Gamepad({ "confirm": ["b", "ls", "rs"], "previous": ["u", "l", "lb", "lt", "lsu", "lsl"], "next": ["d", "r", "rb", "rt", "lsd", "lsr"], "back": ["start", "a"] }, this.keyPressed.bind(this)) pageEvents.send("account", account.loggedIn) } accountForm(){ loader.changePage("account", true) this.mode = "account" this.setAltText(this.getElement("view-title"), account.username) this.items = [] this.inputForms = [] this.shownDiv = "" this.errorDiv = this.getElement("error-div") this.getElement("displayname-hint").innerText = strings.account.displayName this.displayname = this.getElement("displayname") this.displayname.placeholder = strings.account.displayName this.displayname.value = account.displayName this.inputForms.push(this.displayname) this.accountPassButton = this.getElement("accountpass-btn") this.setAltText(this.accountPassButton, strings.account.changePassword) pageEvents.add(this.accountPassButton, ["click", "touchstart"], event => { this.showDiv(event, "pass") }) this.accountPass = this.getElement("accountpass-form") for(var i = 0; i < this.accountPass.length; i++){ this.accountPass[i].placeholder = strings.account.currentNewRepeat[i] this.inputForms.push(this.accountPass[i]) } this.accountPassDiv = this.getElement("accountpass-div") this.accountDelButton = this.getElement("accountdel-btn") this.setAltText(this.accountDelButton, strings.account.deleteAccount) pageEvents.add(this.accountDelButton, ["click", "touchstart"], event => { this.showDiv(event, "del") }) this.accountDel = this.getElement("accountdel-form") this.accountDel.password.placeholder = strings.account.verifyPassword this.inputForms.push(this.accountDel.password) this.accountDelDiv = this.getElement("accountdel-div") this.logoutButton = this.getElement("logout-btn") this.setAltText(this.logoutButton, strings.account.logout) pageEvents.add(this.logoutButton, ["mousedown", "touchstart"], this.onLogout.bind(this)) this.items.push(this.logoutButton) this.endButton = this.getElement("view-end-button") this.setAltText(this.endButton, strings.account.cancel) pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) this.items.push(this.endButton) this.saveButton = this.getElement("save-btn") this.setAltText(this.saveButton, strings.account.save) pageEvents.add(this.saveButton, ["mousedown", "touchstart"], this.onSave.bind(this)) this.items.push(this.saveButton) for(var i = 0; i < this.inputForms.length; i++){ pageEvents.add(this.inputForms[i], ["keydown", "keyup", "keypress"], this.onFormPress.bind(this)) } } showDiv(event, div){ if(event){ if(event.type === "touchstart"){ event.preventDefault() }else if(event.which !== 1){ return } } if(this.locked){ return } var otherDiv = this.shownDiv && this.shownDiv !== div var display = this.shownDiv === div ? "" : "block" this.shownDiv = display ? div : "" switch(div){ case "pass": if(otherDiv){ this.accountDelDiv.style.display = "" } this.accountPassDiv.style.display = display break case "del": if(otherDiv){ this.accountPassDiv.style.display = "" } this.accountDelDiv.style.display = display break } } loginForm(register, fromSwitch){ loader.changePage("login", true) this.mode = register ? "register" : "login" this.setAltText(this.getElement("view-title"), strings.account[this.mode]) this.errorDiv = this.getElement("error-div") this.items = [] this.form = this.getElement("login-form") this.getElement("username-hint").innerText = strings.account.username this.form.username.placeholder = strings.account.enterUsername this.getElement("password-hint").innerText = strings.account.password this.form.password.placeholder = strings.account.enterPassword this.password2 = this.getElement("password2-div") this.remember = this.getElement("remember-div") this.getElement("remember-label").appendChild(document.createTextNode(strings.account.remember)) this.loginButton = this.getElement("login-btn") this.registerButton = this.getElement("register-btn") if(register){ var pass2 = document.createElement("input") pass2.type = "password" pass2.name = "password2" pass2.required = true pass2.placeholder = strings.account.repeatPassword this.password2.appendChild(pass2) this.password2.style.display = "block" this.remember.style.display = "none" this.setAltText(this.loginButton, strings.account.registerAccount) this.setAltText(this.registerButton, strings.account.login) }else{ this.setAltText(this.loginButton, strings.account.login) this.setAltText(this.registerButton, strings.account.register) } pageEvents.add(this.form, "submit", this.onLogin.bind(this)) pageEvents.add(this.loginButton, ["mousedown", "touchstart"], this.onLogin.bind(this)) pageEvents.add(this.registerButton, ["mousedown", "touchstart"], this.onSwitchMode.bind(this)) this.items.push(this.registerButton) if(!register){ this.items.push(this.loginButton) } for(var i = 0; i < this.form.length; i++){ pageEvents.add(this.form[i], ["keydown", "keyup", "keypress"], this.onFormPress.bind(this)) } this.endButton = this.getElement("view-end-button") this.setAltText(this.endButton, strings.account.back) pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) this.items.push(this.endButton) if(fromSwitch){ this.selected = 0 this.endButton.classList.remove("selected") this.registerButton.classList.add("selected") } } getElement(name){ return loader.screen.getElementsByClassName(name)[0] } setAltText(element, text){ element.innerText = text element.setAttribute("alt", text) } keyPressed(pressed, name){ if(!pressed || this.locked){ return } var selected = this.items[this.selected] if(name === "confirm"){ if(selected === this.endButton){ this.onEnd() }else if(selected === this.registerButton){ this.onSwitchMode() }else if(selected === this.loginButton){ this.onLogin() } }else if(name === "previous" || name === "next"){ selected.classList.remove("selected") this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1)) this.items[this.selected].classList.add("selected") assets.sounds["se_ka"].play() }else if(name === "back"){ this.onEnd() } } mod(length, index){ return ((index % length) + length) % length } onFormPress(event){ event.stopPropagation() if(event.type === "keypress" && event.keyCode === 13){ if(this.mode === "account"){ this.onSave() }else{ this.onLogin() } } } onSwitchMode(event){ if(event){ if(event.type === "touchstart"){ event.preventDefault() }else if(event.which !== 1){ return } } if(this.locked){ return } this.clean(true) this.loginForm(this.mode === "login", true) } onLogin(event){ if(event){ if(event.type === "touchstart"){ event.preventDefault() }else if(event.which !== 1){ return } } if(this.locked){ return } var obj = { username: this.form.username.value, password: this.form.password.value } if(!obj.username || !obj.password){ this.error(strings.account.cannotBeEmpty.replace("%s", strings.account[!obj.username ? "username" : "password"])) return } if(this.mode === "login"){ obj.remember = this.form.remember.checked }else{ if(obj.password !== this.form.password2.value){ this.error(strings.account.passwordsDoNotMatch) return } } this.request(this.mode, obj).then(response => { account.loggedIn = true account.username = response.username account.displayName = response.display_name var loadScores = scores => { scoreStorage.load(scores) this.onEnd(false, true, true) pageEvents.send("login", account.username) } if(this.mode === "login"){ this.request("scores/get", false, true).then(response => { loadScores(response.scores) }, () => { loadScores({}) }) }else{ scoreStorage.save().catch(() => {}).finally(() => { this.onEnd(false, true, true) pageEvents.send("login", account.username) }) } }, response => { if(response && response.status === "error" && response.message){ if(response.message in strings.serverError){ this.error(strings.serverError[response.message]) }else{ this.error(response.message) } }else{ this.error(strings.account.error) } }) } onLogout(){ if(event){ if(event.type === "touchstart"){ event.preventDefault() }else if(event.which !== 1){ return } } if(this.locked){ return } account.loggedIn = false delete account.username delete account.displayName var loadScores = () => { scoreStorage.load() this.onEnd(false, true) pageEvents.send("logout") } this.request("logout").then(loadScores, loadScores) } onSave(event){ if(event){ if(event.type === "touchstart"){ event.preventDefault() }else if(event.which !== 1){ return } } if(this.locked){ return } this.clearError() var promises = [] var noNameChange = false if(this.shownDiv === "pass"){ var passwords = [] for(var i = 0; i < this.accountPass.length; i++){ passwords.push(this.accountPass[i].value) } if(passwords[1] === passwords[2]){ promises.push(this.request("account/password", { current_password: passwords[0], new_password: passwords[1] })) }else{ this.error(strings.account.newPasswordsDoNotMatch) return } } if(this.shownDiv === "del" && this.accountDel.password.value){ noNameChange = true promises.push(this.request("account/remove", { password: this.accountDel.password.value }).then(() => { account.loggedIn = false delete account.username delete account.displayName scoreStorage.load() pageEvents.send("logout") return Promise.resolve })) } var newName = this.displayname.value.trim() if(!noNameChange && newName !== account.displayName){ promises.push(this.request("account/display_name", { display_name: newName }).then(response => { account.displayName = response.display_name })) } var error = false var errorFunc = response => { if(error){ return } if(response && response.message){ if(response.message in strings.serverError){ this.error(strings.serverError[response.message]) }else{ this.error(response.message) } }else{ this.error(strings.account.error) } } Promise.all(promises).then(() => { this.onEnd(false, true) }, errorFunc).catch(errorFunc) } onEnd(event, noSound, noReset){ var touched = false if(event){ if(event.type === "touchstart"){ event.preventDefault() touched = true }else if(event.which !== 1){ return } } if(this.locked){ return } this.clean(false, noReset) assets.sounds["se_don"].play() setTimeout(() => { new SongSelect(false, false, touched) }, 500) } request(url, obj, get){ this.lock(true) return new Promise((resolve, reject) => { var request = new XMLHttpRequest() request.open(get ? "GET" : "POST", "api/" + url) pageEvents.load(request).then(() => { this.lock(false) if(request.status !== 200){ reject() return } try{ var json = JSON.parse(request.response) }catch(e){ reject() return } if(json.status === "ok"){ resolve(json) }else{ reject(json) } }, () => { this.lock(false) reject() }) if(obj){ request.setRequestHeader("Content-Type", "application/json;charset=UTF-8") request.setRequestHeader("X-CSRFToken", gameConfig._csrf_token) request.send(JSON.stringify(obj)) }else{ request.send() } }) } lock(isLocked){ this.locked = isLocked if(this.mode === "login" || this.mode === "register"){ for(var i = 0; i < this.form.length; i++){ this.form[i].disabled = isLocked } }else if(this.mode === "account"){ for(var i = 0; i < this.inputForms.length; i++){ this.inputForms[i].disabled = isLocked } } } error(text){ this.errorDiv.innerText = text this.errorDiv.style.display = "block" } clearError(){ this.errorDiv.innerText = "" this.errorDiv.style.display = "" } clean(eventsOnly, noReset){ if(!eventsOnly){ cancelTouch = true this.keyboard.clean() this.gamepad.clean() } if(this.mode === "account"){ if(!noReset){ this.accountPass.reset() this.accountDel.reset() } pageEvents.remove(this.accounPassButton, ["click", "touchstart"]) pageEvents.remove(this.accountDelButton, ["click", "touchstart"]) pageEvents.remove(this.logoutButton, ["mousedown", "touchstart"]) pageEvents.remove(this.saveButton, ["mousedown", "touchstart"]) for(var i = 0; i < this.inputForms.length; i++){ pageEvents.remove(this.inputForms[i], ["keydown", "keyup", "keypress"]) } delete this.errorDiv delete this.displayname delete this.accountPassButton delete this.accountPass delete this.accountPassDiv delete this.accountDelButton delete this.accountDel delete this.accountDelDiv delete this.logoutButton delete this.saveButton delete this.inputForms }else if(this.mode === "login" || this.mode === "register"){ if(!eventsOnly && !noReset){ this.form.reset() } pageEvents.remove(this.form, "submit") pageEvents.remove(this.loginButton, ["mousedown", "touchstart"]) pageEvents.remove(this.registerButton, ["mousedown", "touchstart"]) for(var i = 0; i < this.form.length; i++){ pageEvents.remove(this.registerButton, ["keydown", "keyup", "keypress"]) } delete this.errorDiv delete this.form delete this.password2 delete this.remember delete this.loginButton delete this.registerButton } pageEvents.remove(this.endButton, ["mousedown", "touchstart"]) delete this.endButton delete this.items } }