0

Hello I currently have this input box that takes the user's message and then appends it to a chat box like so:

$('#messageBox').on('keydown', function (evt) {
    if( evt.keyCode == 13 ) {
      $("#chatBox").append(`<div class="UserMessage"><span class="Author" style="color: #fffff;"><span id="ID"></span>User : </span><span class="message">${$( this ).val()}</span></div>`)
    }
} ); 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="messageBox" type="text" placeholder="Your message here:">
<div id="chatBox" style="height: 350px; bottom: 50px;">

I would like to add a feature where it replaces any occurrences of a specific word with an image.

Please note that: The only option I have is to do the replacement after the message has been sent out to the chatBox, since this is just some client-side code, so I won't be able to do the replacement before the message is sent out to the chatBox.

For example, I want to replace any occurrences of :smileyface: with an image link, while also keeping the text. For example; if the user enters Hello:smileyface: it would turn into Hello(the image), if the user enters Hello :smileyface: it would turn into Hello (the image) and if the user enters just :smileyface: it would turn into (the image). So I tried something like this:

$("body").on('DOMSubtreeModified', "#chatBox", function() { // detects when a message it appended to the chatBox
     $(".message").html(function (_, html) {
        return html.replace(/:smileyface:/g,"<img src='https://i.stack.imgur.com/QrKSV.png' width ='35px'/>");
    });
});

However when trying this I got a never-ending error in console, which froze the window:

Uncaught RangeError: Maximum call stack size exceeded.

How can I go about fixing this?

newbie
  • 1,551
  • 1
  • 11
  • 21
  • well you modify the subtree each time so it is a loop.... Wouldn't it be easier to just do the replacement before you update the chat, not with this random listener? – epascarello Mar 19 '18 at 21:19
  • There's a reason why `Be very careful with this event it is easy to cause an infinite loop if you decide to change the DOM inside the event handler` is mentioned on [MDN](https://developer.mozilla.org/en-US/docs/Web/Events/DOMSubtreeModified) – Mathias W Mar 19 '18 at 21:20
  • @epascarello Hi, the only option I have is to do the replacement after it has been detected in the #chatBox, since this is just some client-side code, so I won't be able to do the replacement before the message is sent out to the chatBox – newbie Mar 19 '18 at 21:23
  • So there is no way to alter the chat box code? – epascarello Mar 19 '18 at 21:24
  • @epascarello No, unfortunately not. I have made an edit to the question to make things clearer. – newbie Mar 19 '18 at 21:24
  • well than you need to update the code only when it is has a replacement.... – epascarello Mar 19 '18 at 21:24
  • @epascarello I'm not sure how I would go about doing this. – newbie Mar 19 '18 at 21:26
  • Still not sure why you can not change $('#messageBox').on('keydown', function (evt) .... – epascarello Mar 19 '18 at 21:27
  • I can suggest good tutorial link if you want :) – Mr.ZZ Mar 19 '18 at 21:27
  • @epascarello Reason being I just wrote up that code snippet as an example to help illustrate my question. The code snippet is code I don't have access to. I am simply making a user script, that replaces words in the chatBox with images client-side. – newbie Mar 19 '18 at 21:29
  • 1
    In that case, you could try using the newer standard [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver). You can see an example with jQuery here: https://stackoverflow.com/questions/12596231/can-jquery-selectors-be-used-with-dom-mutation-observers. – tudorpavel Mar 19 '18 at 21:36
  • @tudorpavel Thank you very much, feel free to add an answer so I can accept it and close off this question. – newbie Mar 19 '18 at 21:54
  • @newbie I'm glad I could help. I've edited my initial answer accordingly. – tudorpavel Mar 19 '18 at 22:01

3 Answers3

0

Since the 'keydown' code is not in your control, you could try using the newer standard MutationObserver to detect DOM changes.

You can see an example with jQuery here: Can jQuery selectors be used with DOM mutation observers?

tudorpavel
  • 149
  • 7
0

You are having this done on DOMSubtreeModified. So the first :smileyface: it comes across, it replaces with your image, but that fires another DOMSubtreeModified

I would instead, replace all of the :smileyface: occurrances in your keydown function

var message = $( this ).val();
message = message.replace(/:smileyface:/g,"<img src='https://i.stack.imgur.com/QrKSV.png' width ='35px'/>");
$("#chatBox").append('<div class="UserMessage"><span class="Author" style="color: #fffff;"><span id="ID"></span>User : </span><span class="message">${message}</span></div>');
bcr666
  • 2,157
  • 1
  • 12
  • 23
0

since you mention this is just the client-side code, i suppose there will be some function/event to handle the new data when it is retrieved.

you can then put the "replace code" in that event handler, instead of in a DOMSubtreeModified event (because, like mentioned previously, everytime you update, you will call the DOMSubtreeModified again and again, in an infinite loop)

function newMessageReceived(message){
    message = message.replace(/:smileyface:/g,"<img src='https://i.stack.imgur.com/QrKSV.png' width ='35px'/>");
    $("#chatBox").append(`<div class="UserMessage"><span class="Author" style="color: #fffff;"><span id="ID"></span>User : </span><span class="message">${message}</span></div>`)
}
Fre Timmerman
  • 424
  • 4
  • 12