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(/(? { //create a word object const wordObj = { string: string, type: "word" } //Add it to our body array this.bodyArray.push(wordObj); }); } injectBody(){ //Create empty array to hold strings var stringArray = []; //Extract strings into the empty array this.bodyArray.forEach((wordObj) => { if(wordObj.type == 'word'){ stringArray.push(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; //Inject it into the original string, and add it to string array stringArray.push(wordObj.string.replace('␜',link.outerHTML)); }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; //Inject it into the original string, and add it to string array stringArray.push(wordObj.string.replace('␜',img.outerHTML)); }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; //Inject it into the original string, and add it to string array stringArray.push(wordObj.string.replace('␜',vid.outerHTML)); } }); //Join the strings to fill the chat entry this.chatBody.innerHTML = stringArray.join(""); } 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); } } }