Updated chat post-processor to handle embedded command examples (both ! and /), embedded usernames, and embedded channel names
This commit is contained in:
parent
42d306e1f2
commit
db5fac83ab
|
|
@ -125,7 +125,7 @@ class chatBox{
|
|||
chatEntry.appendChild(chatBody);
|
||||
|
||||
|
||||
this.chatBuffer.appendChild(this.chatPostprocessor.preprocess(chatEntry, data));
|
||||
this.chatBuffer.appendChild(this.chatPostprocessor.postprocess(chatEntry, data));
|
||||
|
||||
//Set size to aspect on launch
|
||||
this.resizeAspect();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ class chatPostprocessor{
|
|||
this.client = client;
|
||||
}
|
||||
|
||||
preprocess(chatEntry, rawData){
|
||||
postprocess(chatEntry, rawData){
|
||||
this.rawData = rawData;
|
||||
//Set current chat nodes
|
||||
this.chatEntry = chatEntry;
|
||||
|
|
@ -15,6 +15,15 @@ class chatPostprocessor{
|
|||
//Inject links into un-processed placeholders
|
||||
this.processLinks();
|
||||
|
||||
//Inject clickable command examples
|
||||
this.processCommandExamples();
|
||||
|
||||
//Inject clickable channel names
|
||||
this.processChannelNames();
|
||||
|
||||
//Inject clickable usernames
|
||||
this.processUsernames();
|
||||
|
||||
//Inject whitespace into un-processed words
|
||||
this.addWhitespace();
|
||||
|
||||
|
|
@ -30,14 +39,17 @@ class chatPostprocessor{
|
|||
splitMessage(){
|
||||
//Create an empty array to hold the body
|
||||
this.messageArray = [];
|
||||
|
||||
//First unescape forward-slashes to keep them from splitting, then..
|
||||
//Split string by word-boundries, with negative lookaheads to exclude file seperators so we don't split link placeholders
|
||||
const splitString = this.rawData.msg.split(/(?<!␜)\b/g);
|
||||
const splitString = this.rawData.msg.replaceAll('/','/').split(/(?<!␜)\b/g);
|
||||
|
||||
//for each word in the splitstring
|
||||
splitString.forEach((string) => {
|
||||
//create a word object
|
||||
const wordObj = {
|
||||
string: string,
|
||||
//re-escape slashes for safety
|
||||
string: string.replaceAll('/','/'),
|
||||
type: "word"
|
||||
}
|
||||
|
||||
|
|
@ -123,15 +135,62 @@ class chatPostprocessor{
|
|||
}
|
||||
|
||||
injectNode(wordObj, vid);
|
||||
}else if(wordObj.type == 'command'){
|
||||
//Create link node
|
||||
const link = document.createElement('a');
|
||||
//Set class
|
||||
link.classList.add('chat-link');
|
||||
//Set href and inner text
|
||||
link.href = "javascript:";
|
||||
link.innerText = wordObj.command;
|
||||
|
||||
//Add chatbox functionality
|
||||
link.addEventListener('click', () => {this.client.chatBox.commandPreprocessor.preprocess(wordObj.command)});
|
||||
|
||||
//We don't have to worry about injecting this into whitespace since there shouldn't be any here.
|
||||
injectionArray.push(link);
|
||||
}else if(wordObj.type == "username"){
|
||||
//Create link node
|
||||
const link = document.createElement('a');
|
||||
//set class
|
||||
link.classList.add(wordObj.color);
|
||||
//Set href and inner text
|
||||
link.href = "javascript:";
|
||||
link.innerText = wordObj.string;
|
||||
|
||||
//add chatbox functionality
|
||||
link.addEventListener('click', () => {this.client.chatBox.chatPrompt.value += `${wordObj.string} `});
|
||||
|
||||
//We don't have to worry about injecting this into whitespace since there shouldn't be any here.
|
||||
injectionArray.push(link);
|
||||
}else if(wordObj.type == "channel"){
|
||||
//Create link node
|
||||
const link = document.createElement('a');
|
||||
//set class
|
||||
link.classList.add('chat-link');
|
||||
//Set href and inner text
|
||||
link.href = `/c/${wordObj.chan}`;
|
||||
link.innerText = wordObj.string;
|
||||
|
||||
//We don't have to worry about injecting this into whitespace since there shouldn't be any here.
|
||||
injectionArray.push(link);
|
||||
}else{
|
||||
console.warn("Unknown chat postprocessor word type:");
|
||||
console.warn(wordObj);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//For each item found in the injection array
|
||||
injectionArray.forEach((item) => {
|
||||
//if it's a string
|
||||
if(typeof item == "string"){
|
||||
//Add it to the chat's innerHTML (it should already be escaped by the server)
|
||||
this.chatBody.innerHTML += item;
|
||||
//Create span (can't add to innerHTML without clobbering sibling DOM nodes)
|
||||
const text = document.createElement('span');
|
||||
//Set text to innerHTML (can't just append as a text node since the message was escaped server-side)
|
||||
text.innerHTML = item;
|
||||
|
||||
this.chatBody.appendChild(text);
|
||||
//Otherwise it should be a DOM node
|
||||
}else{
|
||||
//Append the node to our chat body
|
||||
|
|
@ -167,6 +226,88 @@ class chatPostprocessor{
|
|||
}
|
||||
}
|
||||
|
||||
processCommandExamples(){
|
||||
//for each word object in the body
|
||||
this.messageArray.forEach((wordObj, wordIndex) => {
|
||||
//if the word object hasn't been pre-processed elsewhere
|
||||
if(wordObj.type == "word"){
|
||||
//Get last char of current word with slashes unescaped
|
||||
const unescaped = wordObj.string.replaceAll('/','/')
|
||||
const lastChar = unescaped[unescaped.length - 1];
|
||||
|
||||
//if the last char is !
|
||||
if(lastChar == '!' || lastChar == '/'){
|
||||
//get next word
|
||||
const nextWord = this.messageArray[wordIndex + 1];
|
||||
//if we have another word
|
||||
if(nextWord != null){
|
||||
const command = lastChar + nextWord.string;
|
||||
//Take out the command marker
|
||||
this.messageArray[wordIndex].string = unescaped.slice(0,-1);
|
||||
|
||||
const commandObj = {
|
||||
type: "command",
|
||||
string: nextWord.string,
|
||||
command: command
|
||||
}
|
||||
|
||||
this.messageArray[wordIndex + 1] = commandObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
processChannelNames(){
|
||||
//for each word object in the body
|
||||
this.messageArray.forEach((wordObj, wordIndex) => {
|
||||
//if the word object hasn't been pre-processed elsewhere
|
||||
if(wordObj.type == "word"){
|
||||
//Get last char of current word with slashes unescaped
|
||||
const lastChar = wordObj.string[wordObj.string.length - 1];
|
||||
const secondLastChar = wordObj.string[wordObj.string.length - 2];
|
||||
|
||||
//if the last char is # and the second to last char isn't & (avoid escaped HTML char codes)
|
||||
if(lastChar == '#' && secondLastChar != '&'){
|
||||
//get next word
|
||||
const nextWord = this.messageArray[wordIndex + 1];
|
||||
//if we have another word
|
||||
if(nextWord != null){
|
||||
//Take out the chan marker
|
||||
this.messageArray[wordIndex].string = wordObj.string.slice(0,-1);
|
||||
|
||||
const commandObj = {
|
||||
type: "channel",
|
||||
string: lastChar + nextWord.string,
|
||||
chan: nextWord.string
|
||||
}
|
||||
|
||||
this.messageArray[wordIndex + 1] = commandObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
processUsernames(){
|
||||
//for each word object in the body
|
||||
this.messageArray.forEach((wordObj, wordIndex) => {
|
||||
//if the word object hasn't been pre-processed elsewhere
|
||||
if(wordObj.type == "word"){
|
||||
//Check for user and get their color
|
||||
const color = this.client.userList.colorMap.get(wordObj.string);
|
||||
|
||||
//If the current word is the username of a connected user
|
||||
if(color != null){
|
||||
//Mark it as so
|
||||
this.messageArray[wordIndex].type = "username";
|
||||
//Store their color
|
||||
this.messageArray[wordIndex].color = color;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addWhitespace(){
|
||||
//for each word object in the body
|
||||
this.messageArray.forEach((wordObj, wordIndex) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue