Search code examples
javascriptregexp-replace

UBB Code [textarea] - do not replace \n by <br> within tags [textarea][/textarea]


I currently load a value from my database straight into a hidden textarea.

<textarea name="text" id="text" style="visibility:hidden">
[textarea]Content showing raw [b]HTML[/b] or any other code
Including line breaks </a>[/textarea]
</textarea>

From there I pick up the textarea's content and run it trough several replace arguments with a simple Javascript, like

<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function parser() {  
    post_text=post_text.replace(/\r?\n/g, "<br>"); 
    post_text=post_text.replace(/\[size=1\]/g, "<span style=\"font-size:80%\">"); 
    post_text=post_text.replace(/\[url=(.+?)\](.+?)\[\/url\]/g, "<a href=\"$1\" target=\"_blank\">$2</a>&nbsp;<img src=\"images/link.gif\" style=\"border:0px\">");
    post_text=post_text.replace(/\[url\](.+?)\[\/url\]/g, "<a href=\"$1\" target=\"_blank\">$1</a>&nbsp;<img src=\"images/link.gif\" style=\"border:0px\">");

document.getElementById('vorschau').innerHTML = post_text; 
}, false);
</script>

<div id="vorschau"></div>

to render it into HTML which is then parsed by the Browser, so I do all the formatting of the entries on the Frontend/client side.

However, the textarea may also contain such an UBB tag:

[textarea]Content showing raw [b]HTML[/b] or any other code
Including line breaks </a>[/textarea]

I currently just replace the textarea UBB elements like any other content

post_text=post_text.replace(/\[textarea\]/g, "<textarea id=\"codeblock\" style=\"width:100%;min-height:200px;\">");
post_text=post_text.replace(/\[\/textarea\]/g, "</textarea>");  

The issue with this is that my other code

post_text=post_text.replace(/\r?\n/g, "<br>");
post_text=post_text.replace(/\</g, "&lt;");
post_text=post_text.replace(/\>/g, "&gt;");

Does not skip the content within the [textarea][/textarea] elements resulting in a textarea filled with this:

Content showing raw <b>HTML</b> or any other code<br>Including line breaks &lt;/a&gt;

Above example

So how do I prevent to replace anything within [textarea][/textarea] (which can occur more than once in id="text")?


Solution

  • What you might do, is use a dynamic pattern that captures from [textarea] till [/textarea] in group 1, and use an alternation to match what you want to replace.

    Then use a callback function for replace. Check if group 1 exists, and if it does return it unmodified. If it does not, we have a match outside of the text area.

    An example of the pattern with the alternation and match for <

    (\[textarea][^]*\[\/textarea])|<
    
    • (\[textarea][^]*\[\/textarea]) Capture group 1, match from [textarea] till [/textarea]
    • | Or
    • < Match literally

    Regex demo

    Note to double escape the backslash in the RegExp constructor.

    (Assuming this is the right order of replacements:)

    const replacer = (text, find, replace) => text.replace(
      new RegExp(`(\\[textarea][^]*\\[\\/textarea])|${find}`, "g"),
      (m, g1) => g1 ? g1 : replace
    );
    document.addEventListener('DOMContentLoaded', function parser() {
    
      let post_text = document.getElementById('text').value;
      post_text = post_text.replace(/\[size=1]/g, "<span style=\"font-size:80%\">");
      post_text = post_text.replace(/\[url=(.+?)](.+?)\[\/url\]/g, "<a href=\"$1\" target=\"_blank\">$2</a>&nbsp;<img src=\"images/link.gif\" style=\"border:0px\">");
      post_text = post_text.replace(/\[url](.+?)\[\/url]/g, "<a href=\"$1\" target=\"_blank\">$1</a>&nbsp;<img src=\"images/link.gif\" style=\"border:0px\">");
      post_text = replacer(post_text, "\\r?\\n", "<br>");
      post_text = replacer(post_text, "<", "&lt;");
      post_text = replacer(post_text, ">", "&gt;");
      post_text = post_text.replace(/\[textarea]/g, "<textarea id=\"codeblock\" style=\"width:100%;min-height:200px;\">");
      post_text = post_text.replace(/\[\/textarea]/g, "</textarea>");
    
      document.getElementById('vorschau').innerHTML = post_text;
    }, false);
    <textarea name="text" id="text" rows="10" cols="60">
    [textarea]Content showing raw [b]HTML[/b] or any other code
    Including line breaks </a>[/textarea]
        
        
        < here and > here and
    </textarea>
    
    <div id="vorschau"></div>