canopy/www/js/channel/chatPostprocessor.js

180 lines
6.8 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class chatPostprocessor{
constructor(){
}
preprocess(chatEntry, rawData){
this.rawData = rawData;
//Set current chat nodes
this.chatEntry = chatEntry;
this.chatBody = this.chatEntry.querySelector(".chat-entry-body");
//Split the chat body into an array of objects representing each word
//We could pass this through arguments but these functions wont be very interoperable anyways since they expect a purpose-made hashtable
this.splitBody();
//Inject links into un-processed placeholders
this.processLinks();
//Inject whitespace into un-processed words
this.addWhitespace();
//Handle non-standard chat types
this.handleChatType();
//Inject the pre-processed chat into the chatEntry node
this.injectBody();
//Return the pre-processed node
return this.chatEntry;
}
splitBody(){
//Create an empty array to hold the body
this.bodyArray = [];
//Split string by word-boundries, with negative/forward lookaheads to exclude file seperators so we don't split link placeholders
const splitString = this.chatBody.innerHTML.split(/(?<!␜)\b/g);
//for each word in the splitstring
splitString.forEach((string) => {
//create a word object
const wordObj = {
string: string,
type: "word"
}
//Add it to our body array
this.bodyArray.push(wordObj);
});
}
injectBody(){
//Clear our chat body
this.chatBody.innerHTML = "";
//Extract strings into the empty array
this.bodyArray.forEach((wordObj) => {
if(wordObj.type == 'word'){
//Inject current wordObj string into the chat body
this.chatBody.innerHTML += wordObj.string
}else if(wordObj.type == 'link'){
//Create a link node from our link
const link = document.createElement('a');
link.classList.add('chat-link');
link.href = wordObj.link;
link.innerHTML = wordObj.link;
//Append node to chatBody
this.injectNode(wordObj, link);
}else if(wordObj.type == 'image'){
//Create an img node from our link
const img = document.createElement('img');
img.classList.add('chat-img');
img.src = wordObj.link;
//stringArray.push(wordObj.string.replace('␜',img.outerHTML));
//Append node to chatBody
this.injectNode(wordObj, img);
}else if(wordObj.type == 'video'){
//Create a video node from our link
const vid = document.createElement('video');
vid.classList.add('chat-video');
vid.src = wordObj.link;
vid.controls = false;
vid.autoplay = true;
vid.loop = true;
vid.muted = true;
//stringArray.push(wordObj.string.replace('␜',vid.outerHTML));
this.injectNode(wordObj, vid);
}
});
}
//Like string.replace except it actually injects the node so we can keep things like event handlers
injectNode(wordObj, node, placeholder = '␜'){
//Split string by the placeholder so we can keep surrounding whitespace
const splitWord = wordObj.string.split(placeholder, 2);
//Append the first half of the string
this.chatBody.innerHTML += splitWord[0];
//Append the node
this.chatBody.appendChild(node);
//Append the second half of the string
this.chatBody.innerHTML += splitWord[1];
}
addWhitespace(){
//for each word object in the body
this.bodyArray.forEach((wordObj, wordIndex) => {
//if the word object hasn't been pre-processed elsewhere
if(wordObj.type == "word"){
var wordArray = [];
//Add invisible whitespace in-between characters to keep it from breaking page layout
this.bodyArray[wordIndex].string.split("").forEach((char, charIndex) => {
wordArray.push(char);
//After eight characters
if(charIndex > 8){
//Push an invisible line-break character between every character
wordArray.push("");
}
});
this.bodyArray[wordIndex].string = wordArray.join("");
}
});
}
processLinks(){
//If we don't have links
if(this.rawData.links == null){
//Don't bother
return;
}
this.rawData.links.forEach((link, linkIndex) => {
this.bodyArray.forEach((wordObj, wordIndex) => {
//Check current wordobj for link (placeholder may contain whitespace with it)
if(wordObj.string.match(`${linkIndex}`)){
//Set current word object in the body array to the new link object
this.bodyArray[wordIndex] = {
//Don't want to use a numbered placeholder to make this easier during body injection
//but we also don't want to clobber any surrounding whitespace
string: wordObj.string.replace(`${linkIndex}`, '␜'),
link: link.link,
type: link.type
}
}
})
});
}
handleChatType(){
if(this.rawData.type == "whisper"){
//add whisper class
this.chatBody.classList.add('whisper');
}else if(this.rawData.type == "announcement"){
//Squash the high-level
this.chatEntry.querySelector('.high-level').remove();
//Get the username and make it into an announcement title (little hacky but this *IS* postprocessing)
const userNode = this.chatEntry.querySelector('.chat-entry-username');
userNode.innerHTML = `${userNode.innerHTML.slice(0,-2)} Announcement`;
//Add/remove relevant classes
userNode.classList.remove('chat-entry-username');
userNode.classList.add('announcement-title');
this.chatBody.classList.add('announcement-body');
this.chatEntry.classList.add('announcement');
}else if(this.rawData.type == "toke" || this.rawData.type == "tokewhisper"){
//Squash the high-level
this.chatEntry.querySelector('.high-level').remove();
//remove the username
this.chatEntry.querySelector('.chat-entry-username').remove();
//Add toke/tokewhisper class
this.chatBody.classList.add(this.rawData.type);
}
}
}