2

I am currently writing my own BBCode parser. Now what I would like to do is allow the user to enter BBCode, and then it will write it into HTML and display it has HTML. Yet if they enter HTML it will just show it as plain old HTML. Here is what I have so far:

var replacebbcode = $('#textareainput').val().replace(/(\[((\/?)(b|u|i|s|sub|sup))\])/gi, '<$2>');
$('#posttextareadisplay').html(replacebbcode);

In the above I am just replacing all BBCode with HTML tags. Problem is if a user directly enter HTML it will use that as well. So basically, how can I display BBCode as HTML, but actual HTML as text?

Michael Jones
  • 2,222
  • 18
  • 32

2 Answers2

1

Set the target's text() with the full text; so your HTML tags will be encoded. Then do the BBCode replacement on the encoded HTML:

$('#posttextareadisplay').text( $('#textareainput').val() );

var replacebbcode = $('#posttextareadisplay').
  html().
  replace(/(\[((\/?)(b|u|i|s|sub|sup))\])/gi, '<$2>');

$('#posttextareadisplay').html( replacebbcode );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<textarea name="" id="textareainput" cols="30" rows="10">
  [b]bold[/b] &lt;bold>bold&lt;/bold>
</textarea>

<p id="posttextareadisplay"></p>
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
  • Hello, thank you for replying! :) Problem is, the text will not update. I am making this a live preview (as you know probably). Here is my JSFiddle: https://jsfiddle.net/18ehuy5t/ – Michael Jones Apr 30 '15 at 21:27
  • Should be grabbing the `val()`, not text, of the `textarea`. Fixed above. Also fixed your fiddle: https://jsfiddle.net/18ehuy5t/1/ – Paul Roub Apr 30 '15 at 21:35
  • Thank you! :) Also while you are still here, I have one more question you may be able to answer. If a user enters this in there Textarea lets say: `Hello, my name is Michael. What is your name?`, then they try to highlight the second `name`, and style it. It will then just style the first `name`. It is because of the `replace`, are there any other ways to replace the text in the textarea correctly? Do you understand my question? :) – Michael Jones Apr 30 '15 at 21:40
  • Basically, yes. See questions such as http://stackoverflow.com/questions/3964710/replacing-selected-text-in-the-textarea to get it right. – Paul Roub Apr 30 '15 at 21:45
0

If you want to replace with regular html tags and restrict to only specific BB tags. This is how it's done with a little help from jQuery and Regular Expression:

const replaceBBCodeAsElements = (jElement, tagMapping = {}) =>
  jElement.html(jElement.html().replace(/\[(?<tag>\w+)\](.+?)\[\/\k<tag>\]/g,
      (...{ 0: original, 1: tagName, 2: tagContent }) =>
          tagMapping.hasOwnProperty(tagName) ? $(tagMapping[tagName]).html(tagContent)[0].outerHTML : original
  ));

And here is an example of using this function:

const replaceBBCodeAsElements = (jElement, tagMapping = {}) =>
  jElement.html(jElement.html().replace(/\[(?<tag>\w+)\](.+?)\[\/\k<tag>\]/g,
      (...{ 0: original, 1: tagName, 2: tagContent }) =>
          tagMapping.hasOwnProperty(tagName) ? $(tagMapping[tagName]).html(tagContent)[0].outerHTML : original
  ));

const config = {
  'a': '<div class="tag some-special-a-tag" />',
  'object': '<span class="tag some-special-object-tag" />',
  'pre': '<p class="tag some-special-pre-tag" />',
  'test': '<div data-hello="world" class="tag some-special-test-tag" />',
};

$("#input").bind("input", function() {
  const jRes = $("#result");
  jRes.text(this.value);
  replaceBBCodeAsElements(jRes, config);
}).trigger('input');
#input {
  width: 400px;
  height: 100px;
}

#result {
  white-space: pre-wrap;
}

.tag {
 display: inline-block;
 background: rgba(0,0,0,.1);
 padding: 0 4px;
 border-radius: 5px;
 font-family: monospace;
 font-weight: bold;
 margin: 0;
 box-shadow: 0 0 10px 0 rgba(0,0,0,.6);
}

.some-special-a-tag {
 background: rgba(255,0,0,.1);
}

.some-special-object-tag {
 background: rgba(0,255,0,.1);
}

.some-special-pre-tag {
 background: rgba(0,0,255,.1);
}

.some-special-test-tag {
 background: rgba(0,255,255,.1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<textarea id="input">This &lt;p&gt;is&lt;/p&gt; 
a [a]test[/a] text [pre]with[/pre] [b]some[/b] va[test]lu[/test]e.

And this is how it looks [object]when a [pre]tag inside[/pre] other[/object] tag</textarea>

<div id="result"></div>

The above example, will parse only [a], [object], [pre] and [test] BB tags and convert them according to the creation element they are pointing to.

Note, that the minimum required version of JS is ES2018, because of the RegExp Named Group support.

Slavik Meltser
  • 9,712
  • 3
  • 47
  • 48