/*Canopy - The next generation of stoner streaming software Copyright (C) 2024-2025 Rainbownapkin and the TTN Community This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ class profileUpdatePrompt{ constructor(field){ this.field = field; this.contentNode = document.querySelector(`#profile-${field}-content`); this.promptNode = document.querySelector(`#profile-${field}-prompt`); if(this.promptNode != null){ this.setupInput(); } } setupInput(){ this.contentNode.addEventListener('click', this.popPrompt.bind(this)); this.promptNode.addEventListener('keydown', this.closePrompt.bind(this)); } popPrompt(){ this.promptNode.style.display = 'inline'; this.promptNode.focus(); } closePrompt(event){ //Check if we're finished const fin = event.key == "Escape" || event.key == "Enter"; //IF we are if(fin){ //Display the prompt this.promptNode.style.display = 'none'; } //Return whether or not we're done return fin; } } class profileUpdateTextPrompt extends profileUpdatePrompt{ constructor(field, fillPrompt = false){ //call derived constructor super(field); //Set fill prompt this.fillPrompt = fillPrompt; } popPrompt(){ //Call derived method super.popPrompt(); //If we're filling the prompt if(this.fillPrompt){ //Fill the prompt content and placeholder this.promptNode.value = this.contentNode.textContent; this.promptNode.placeholder = this.field; //otherwise }else{ //Just fill the placeholder this.promptNode.placeholder = this.contentNode.textContent; } //Hide content this.contentNode.style.display = 'none'; } async closePrompt(event){ //Call derived constructor and check if we're finished, assuming we're finished... if(super.closePrompt(event)){ //Display this.contentNode.style.display = 'inline-block'; //If we're not cancelling if(event.key == "Enter"){ //Create empty update object let updateObj = {}; //Fill field updateObj[this.field] = this.promptNode.value; //Send er' off const update = await utils.ajax.updateProfile(updateObj); //Fill content from update this.contentNode.innerHTML = update[this.field]; } } } } class profileUpdateImagePrompt extends profileUpdatePrompt{ constructor(){ //call derived constructor super('img'); } popPrompt(){ //Call derived method super.popPrompt(); this.promptNode.placeholder = this.contentNode.src; } async closePrompt(event){ //Call derived constructor super.closePrompt(event); //If we're not cancelling if(event.key == "Enter"){ //Create empty update object let updateObj = {}; //Fill field updateObj[this.field] = this.promptNode.value; //Send er' off const update = await utils.ajax.updateProfile(updateObj); //Fill content from update this.contentNode.src = update[this.field]; } } } class passwordResetPrompt{ constructor(){ this.oldPassNode = document.querySelector('#account-settings-password-reset-old'); this.newPassNode = document.querySelector('#account-settings-password-reset-new'); this.confirmPassNode = document.querySelector('#account-settings-password-reset-confirm'); this.setupInput(this.oldPassNode); this.setupInput(this.newPassNode); this.setupInput(this.confirmPassNode); } setupInput(node){ if(node != null){ node.addEventListener("keydown", this.update.bind(this)); } } async update(event){ var hasVal = (this.oldPassNode.value && this.newPassNode.value && this.confirmPassNode.value); if((!event || event.key == "Enter") && hasVal){ if(this.newPassNode.value == this.confirmPassNode.value){ const updateObj = {}; updateObj.passChange = { oldPass: this.oldPassNode.value, newPass: this.newPassNode.value, confirmPass: this.confirmPassNode.value }; const response = await utils.ajax.updateProfile(updateObj); if(response != null){ //Return user homepage after good pass change, as we've probably been logged out by the server for security. window.location.pathname = '/'; } } } } } class tokeList{ constructor(){ this.tokeList = document.querySelector('#profile-tokes'); this.tokeListLabel = document.querySelector('.profile-toke-count'); this.tokeListToggleIcon = document.querySelector('#toggle-toke-list'); this.setupInput(); } setupInput(){ this.tokeListLabel.addEventListener('click', this.toggleTokeList.bind(this)); } toggleTokeList(){ if(this.tokeList.style.visibility == "visible"){ this.tokeList.style.visibility = "collapse"; this.tokeListToggleIcon.classList.replace("bi-caret-down-fill","bi-caret-left-fill"); }else{ this.tokeList.style.visibility = "visible"; this.tokeListToggleIcon.classList.replace("bi-caret-left-fill","bi-caret-down-fill"); } } } class deleteAccountButton{ constructor(){ this.deleteLink = document.querySelector('#account-settings-delete-button'); if(this.deleteLink != null){ this.setupInput(); } } setupInput(){ this.deleteLink.addEventListener("click",this.deletePrompt.bind(this)); } async deletePrompt(event){ this.popup = new deleteAccountPopup(); } } class deleteAccountPopup{ constructor(){ this.popup = new canopyUXUtils.popup("nukeUser", true, this.asyncConstructor.bind(this)); } asyncConstructor(){ this.passwordPrompt = document.querySelector("#delete-account-popup-password"); this.setupInput(); } setupInput(){ this.passwordPrompt.addEventListener("keydown", this.nukeAccount.bind(this)); } async nukeAccount(event){ if(event.key == "Enter"){ await utils.ajax.deleteAccount(event.target.value); } } } //Object Instantiation const imgPrompt = new profileUpdateImagePrompt(); const pronounsPrompt = new profileUpdateTextPrompt('pronouns'); const signaturePrompt = new profileUpdateTextPrompt('signature'); const bioPrompt = new profileUpdateTextPrompt('bio', true); const profileTokeList = new tokeList(); const accountPassResetPrompt = new passwordResetPrompt(); const accountDeleteButton = new deleteAccountButton();