canopy/www/js/channel/panels/pmPanel.js

327 lines
11 KiB
JavaScript

/*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 <https://www.gnu.org/licenses/>.*/
/**
* Class representing the settings panel
* @extends panelObj
*/
class pmPanel extends panelObj{
/**
* Instantiates a new Panel Object
* @param {channel} client - Parent client Management Object
* @param {Document} panelDocument - Panel Document
*/
constructor(client, panelDocument){
super(client, "Private Messaging", "/panel/pm", panelDocument);
/**
* String to hold name of currently active sesh
*/
this.activeSesh = "";
this.defineListeners();
}
closer(){
}
docSwitch(){
this.startSeshButton = this.panelDocument.querySelector('#pm-panel-start-sesh');
this.seshList = this.panelDocument.querySelector('#pm-panel-sesh-list');
this.seshBuffer = this.panelDocument.querySelector('#pm-panel-sesh-buffer');
this.seshPrompt = this.panelDocument.querySelector('#pm-panel-message-prompt');
this.seshSendButton = this.panelDocument.querySelector('#pm-panel-send-button');
this.setupInput();
this.renderSeshList();
//If we have an active sesh
if(this.activeSesh != null && this.activeSesh != ""){
//Render messages
this.renderMessages();
}
//Call derived method
super.docSwitch();
}
/**
* Defines network related event listeners
*/
defineListeners(){
this.client.pmSocket.on("message", this.handlePM.bind(this));
this.client.pmSocket.on("sent", this.handlePM.bind(this));
}
/**
* Defines input-related event handlers
*/
setupInput(){
this.startSeshButton.addEventListener('click', this.startSesh.bind(this));
this.seshPrompt.addEventListener("keydown", this.send.bind(this));
this.seshSendButton.addEventListener("click", this.send.bind(this));
}
startSesh(event){
new startSeshPopup(event, this.client, this.renderSeshList.bind(this), this.ownerDoc);
}
handlePM(data){
const nameObj = pmHandler.genSeshName(data);
//If this message is for the active sesh
if(nameObj.name == this.activeSesh){
//Render out the newest message
this.renderMessage(data);
}else{
//pull current session entry if it exists
const curEntry = this.panelDocument.querySelector(`[data-id="${nameObj.name}"]`);
//If it doesn't exist
if(curEntry == null){
//Re-render out the sesh list
this.renderSeshList();
}
}
}
/**
* sends private message from sesh prompt to server
* @param {Event} event - Event passed down from Event Handler
*/
send(event){
if((!event || !event.key || event.key == "Enter") && this.seshPrompt.value && this.activeSesh != ''){
//Pull current sesh from sesh list
const sesh = this.client.pmHandler.seshList.get(this.activeSesh);
//Preprocess message from prompt
const preprocessedMessage = this.client.chatBox.commandPreprocessor.preprocess(this.seshPrompt.value);
//If preprocessedMessage had it's send flag thrown as false
if(preprocessedMessage != false){
//Stick recipients into the pre-processed message
preprocessedMessage.recipients = sesh.recipients;
//Send message out to server
this.client.pmSocket.emit("pm", preprocessedMessage);
}
//Clear our prompt
this.seshPrompt.value = "";
}
}
/**
* Render out current sesh array to sesh list UI
*/
renderSeshList(){
//Clear out the sesh list
this.seshList.innerHTML = "";
//Assemble temporary array from client PM Handler sesh list
const seshList = Array.from(this.client.pmHandler.seshList);
//If we have existing sessions and no active sesh
if(this.activeSesh == "" && seshList[0] != null){
//Enable UI elements
this.seshPrompt.disabled = false;
this.seshSendButton.disabled = false;
//Render out messages
this.renderMessages();
//Set the first one as active
this.activeSesh = seshList[0][1].id;
}
//For each session tracked by the pmHandler
for(const seshEntry of seshList){
this.renderSeshListEntry(seshEntry[1]);
}
}
/**
* Renders out a given messaging sesh to the sesh list UI
*/
renderSeshListEntry(sesh){
//Create container div
const entryDiv = document.createElement('div');
//Set conatiner div classes
entryDiv.classList.add('pm-panel-sesh-list-entry','interactive');
//Set dataset sesh name
entryDiv.dataset.id = sesh.id;
//If the current entry is the active sesh
if(sesh.id == this.activeSesh){
//mark it as such
entryDiv.classList.add('positive');
}
//Create sesh label
const seshLabel = document.createElement('p');
//Create human-readable label out of members array
seshLabel.textContent = utils.unescapeEntities(sesh.id);
//append sesh label to entry div
entryDiv.appendChild(seshLabel);
//Append entry div to sesh list
this.seshList.appendChild(entryDiv);
//Add input-related event listener for entry div
entryDiv.addEventListener('click', this.selectSesh.bind(this));
}
selectSesh(event){
//Attempt to pull previously active sesh item from list
const wasActive = this.panelDocument.querySelector('.positive');
//If there was an active sesh
if(wasActive != null){
//Remove active sesh class from old item
wasActive.classList.remove('positive');
}
//Pull new active sesh name from target dataset
this.activeSesh = event.target.dataset.id;
//Set new sesh as active sesh
event.target.classList.add('positive');
//Re-render message buffer
this.renderMessages();
}
renderMessages(){
//Empty out the sesh buffer
this.seshBuffer.innerHTML = "";
//Pull sesh from pmHandler
const sesh = this.client.pmHandler.seshList.get(this.activeSesh);
//If the sesh is real
if(sesh != null){
//for each message in the sesh
for(const message of sesh.messages){
//Render out messages to the buffer
this.renderMessage(message);
}
}
}
/**
* Renders message out to PM Panel Message Buffer
* @param {Object} message - Message to render
*/
renderMessage(message){
//Run postprocessing functions on chat message
const postprocessedMessage = client.chatBox.chatPostprocessor.postprocess(message);
//Append message to buffer
this.seshBuffer.appendChild(postprocessedMessage);
}
}
/**
* Class representing pop-up dialogue to start a private messaging sesh
*/
class startSeshPopup{
/**
* Instantiates a new schedule media Pop-up
* @param {Event} event - Event passed down from Event Listener
* @param {channel} client - Parent Client Management Object
* @param {String} url - URL/link to media to queue
* @param {String} title - Title of media to queue
* @param {Function} cb - Callback function, passed upon pop-up creation
* @param {Document} doc - Current owner documnet of the panel, so we know where to drop our pop-up
*/
constructor(event, client, cb, doc){
/**
* Parent Client Management Object
*/
this.client = client;
/**
* Callback function, passed upon pop-up creation
*/
this.cb = cb;
//Create media popup and call async constructor when done
//unfortunately we cant call constructors asyncronously, and we cant call back to this from super, so we can't extend this as it stands :(
/**
* canopyUXUtils.popup() object
*/
this.popup = new canopyUXUtils.popup('/startChatSesh', true, this.asyncConstructor.bind(this), doc);
}
/**
* Continuation of object construction, called after child popup object construction
*/
asyncConstructor(){
//Grab required UI elements
this.startSeshButton = this.popup.contentDiv.querySelector('#pm-sesh-popup-button');
this.usernamePrompt = this.popup.contentDiv.querySelector('#pm-sesh-popup-prompt');
//Setup input
this.setupInput();
}
/**
* Defines input-related Event Handlers
*/
setupInput(){
//Setup input
this.startSeshButton.addEventListener('click', this.startSesh.bind(this));
this.popup.popupDiv.addEventListener('keydown', this.startSesh.bind(this));
}
/**
* Handles sending request to schedule item to the queue
* @param {Event} event - Event passed down from Event Listener
*/
startSesh(event){
//If we clicked or hit enter
if(event.key == null || event.key == "Enter"){
/*
//Cook a new sesh from
const newSesh = new pmSesh({
//Split usernames by space
sender: this.client.user.user,
recipients: this.usernamePrompt.value.split(" ")
});
//Pop new sesh into pmHandler
this.client.pmHandler.seshList.set(newSesh.id, newSesh);
*/
//Send message out to server
this.client.pmSocket.emit("pm", {
recipients: this.usernamePrompt.value.split(" "),
msg: ""
});
//If we have a function
if(typeof this.cb == "function"){
//Call any callbacks we where given
this.cb();
}
//Close the popup
this.popup.closePopup();
}
}
}