/*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 .*/ //Base Class class profileEditPrompt{ constructor(field, content, useTextArea = false){ this.field = field; this.useTextArea = useTextArea; this.content = content; this.link = document.querySelector(`#profile-${field}-edit`); //Bail out if something ain't right if(!this.link || !this.content){ return; } this.setupPrompt(); } setupPrompt(){ if(this.link != null){ this.link.addEventListener("click", this.prompt.bind(this)); } } prompt(){ //Create input element if(this.useTextArea){ this.prompt = document.createElement("textArea"); }else{ this.prompt = document.createElement("input"); } //Setup properties this.prompt.id = `profile-${this.field}-prompt`; this.prompt.classList.add("profile-edit-prompt"); if(this.field == "img"){ this.prompt.placeholder = this.content.src; }else{ this.prompt.placeholder = this.content.innerHTML; } //Setup event listener this.prompt.addEventListener("keydown", this.update.bind(this)); //replace label this.content.replaceWith(this.prompt); } async update(event){ if((!event || event.key == "Enter") && this.prompt.value){ //setup object var updateObj = {}; updateObj[this.field] = this.prompt.value; //contact server, and collect response var updated_content = (await utils.ajax.updateProfile(updateObj))[this.field]; //Update label if(updated_content != null){ if(this.field == "img"){ this.content.src = updated_content; }else{ this.content.innerHTML = updated_content; } } this.finish(); }else if(event.key == "Escape" || event.key == "Enter"){ this.finish(); } } finish(){ this.prompt.replaceWith(this.content); } } class profileTextEditPrompt extends profileEditPrompt{ constructor(field, useTextArea = false){ //Get content based on field name var content = document.querySelector(`#profile-${field}-content`); //Derived Constructor super(field, content, useTextArea); } prompt(){ super.prompt(); } async update(event){ await super.update(event) } } //Child Classes class profileImgEditPrompt extends profileEditPrompt{ constructor(){ //Get content based on field name var content = document.querySelector(`#profile-img`); //Derived constructor super("img", content, false); } } 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.checkVisibility()){ this.tokeList.style.display = "none"; this.tokeListToggleIcon.classList.replace("bi-caret-down-fill","bi-caret-left-fill"); }else{ this.tokeList.style.display = "block"; this.tokeListToggleIcon.classList.replace("bi-caret-left-fill","bi-caret-down-fill"); } } } class deleteAccountButton{ constructor(){ this.deleteLink = document.querySelector('#account-settings-delete-button'); 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 new profileTextEditPrompt("signature"); new profileTextEditPrompt("bio", true); new profileImgEditPrompt(); new tokeList(); new passwordResetPrompt(); new deleteAccountButton();