12

i'm trying to make my own markdown-able textarea like Stackoverflow has done. The goal is to allow people to type **blah blah** in a textarea and have the output in a div be <span style="font-weight:bold;">blah blah</span>.

I'm having trouble with the javascript to find and replace to the **asterisks with the HTML.

here's a jsfiddle which has gotten the party started: http://jsfiddle.net/trpeters1/2LAL4/14/

here's the JS on that just to show you where I'm at:

$(document.body).on('click', 'button', function() {

var val=$('textarea').val();

var bolded=val.replace(/\**[A-z][0-9]**/gi, '<span style="font-weight:bold;">"'+val+'" </span>');

$('div').html(bolded);
});

and the HTML...

<textarea></textarea>
<div></div><button type="button">Markdownify</button>

any thoughts would be greatly appreciated!

thanks, tim

tim peterson
  • 23,653
  • 59
  • 177
  • 299
  • The problem is solved, **[Check my answer!](https://stackoverflow.com/a/64689534/14559436)** – 001 Nov 05 '20 at 00:32

8 Answers8

22

The other answers fail when a char is immediately before or after the asterisks.

This works like markdown should:

function bold(text){
    var bold = /\*\*(.*?)\*\*/gm;
    var html = text.replace(bold, '<strong>$1</strong>');            
    return html;
}
    
var result = bold('normal**bold**normal **b** n.');
document.getElementById("output").innerHTML = result;
div { color: #aaa; }
strong { color: #000; }
<div id="output"></div>
Justin
  • 26,443
  • 16
  • 111
  • 128
  • 2
    This doesn't work if the first occurrence is followed by another occurrence which only contains one letter http://jsfiddle.net/b5gvajsx/9/ – LaurelT Aug 29 '17 at 16:16
  • If someone figures out how to solve the issue LaurelB mentioned ^, please post a comment. – Justin Oct 11 '18 at 17:16
  • 2
    In a one-liner `return text.replace(/\*\*(\S(.*?\S)?)\*\*/gm, '$1')` – Patrick Jun 12 '19 at 14:19
  • 2
    Removing all the \S seems to have resolved LaurelB's issue. Updated answer. – Justin Feb 06 '20 at 21:14
4

None of the provided answers works in all cases. For example, the other solutions wont work if we have a space next to the double star, ie:

This will ** not ** be bold

So I wrote this:

function markuptext(text,identifier,htmltag)
{
    var array = text.split(identifier);
    var previous = "";
    var previous_i;
    for (i = 0; i < array.length; i++) {
        if (i % 2)
        {
            //odd number
        }
        else if (i!=0)
        {
            previous_i = eval(i-1);
            array[previous_i] = "<"+htmltag+">"+previous+"</"+htmltag+">";
        }
        previous = array[i];
    }
    var newtext = "";
    for (i = 0; i < array.length; i++) {
        newtext += array[i];
    }
    return newtext;
}

Just call it like this:

thetext = markuptext(thetext,"**","strong");

and it will work in all cases. Of course, you can also use it with other identifiers/html-tags as you like (the stackoverflow preview should have this too).

  • `"testing regex in *javascript* when using different **stuff**"` with `markuptext(thetext,"*","strong");` returns `"testing regex in javascript when using different stuff"` – Animismus Sep 02 '19 at 14:23
2

Choose the perfect regex that will fit your needs. If you don't want styling to span through new line and also using ([^*<\n]+) makes sure at least one character is in between styles or else ** without a character in-between will result will become invisible.

function format_text(text){
return text.replace(/(?:\*)([^*<\n]+)(?:\*)/g, "<strong>$1</strong>")
     .replace(/(?:_)([^_<\n]+)(?:_)/g, "<i>$1</i>")
      .replace(/(?:~)([^~<\n]+)(?:~)/g, "<s>$1</s>")
      .replace(/(?:```)([^```<\n]+)(?:```)/g, "<tt>$1</tt>")
}

•The downside to the above code is that, you can't nest styles i.e *_Bold and italic_*

To allow nested styles use this

format_text(text){
return text.replace(/(?:\*)(?:(?!\s))((?:(?!\*|\n).)+)(?:\*)/g,'<b>$1</b>')
   .replace(/(?:_)(?:(?!\s))((?:(?!\n|_).)+)(?:_)/g,'<i>$1</i>')
   .replace(/(?:~)(?:(?!\s))((?:(?!\n|~).)+)(?:~)/g,'<s>$1</s>')
   .replace(/(?:--)(?:(?!\s))((?:(?!\n|--).)+)(?:--)/g,'<u>$1</u>')
   .replace(/(?:```)(?:(?!\s))((?:(?!\n|```).)+)(?:```)/g,'<tt>$1</tt>');

// extra:
// --For underlined text--
// ```Monospace font```
}

If you want your style to span through new line, then remove \n from the regex. Also if your new line is html break tag, you can replace \n with <br>

Thank me later!

The concise
  • 444
  • 4
  • 12
1

Why create from scratch? With so many open source editors out there, you should pick a code base you like & go from there. http://oscargodson.github.com/EpicEditor/ http://markitup.jaysalvat.com/home/

tomByrer
  • 1,105
  • 12
  • 21
  • hi tom, thanks for these suggestions, EpicEditor is quite nice. However, these editors are way too involved for my needs. I'd rather spend my time learning how to code the simple features I want (just bold, italics, hyperlinking text) than trying to deconvolute these complicated codebases. The more boring reason is I've already spend **ALOT** of time this weekend getting ridiculously frustrated by iframe behavior in various browsers and most editors including the ones you mention use iframes. So I just can't take that anymore. – tim peterson Apr 16 '12 at 04:05
  • 1
    Ah OK Tim, how about this: https://github.com/coreyti/showdown/blob/master/src/showdown.js Explains the RegEx decently. Also for cleaner code, but less comments: https://github.com/chjj/marked/blob/master/lib/marked.js – tomByrer Apr 16 '12 at 05:11
  • Please keep in touch @tim on what is best for you; I want to create my own version of MarkDown also. I want to create codes that make sense to me:
    /italic/ *bold* _underline_ -deleted- [Maybe url|www.url.com]
    . I hope you can trail blase for me please :)
    – tomByrer Apr 17 '12 at 05:49
  • hi tom, i actually have it working quite well now thanks to everyone's help, check out this demo: http://jsfiddle.net/trpeters1/2LAL4/49/ – tim peterson Apr 17 '12 at 06:06
  • Cool, works here! One thing though: normally you'd want to https://en.wikipedia.org/wiki/Separation_of_presentation_and_content so I did: http://jsfiddle.net/tomByrer/2LAL4/50/ (BTW, MarkDown uses instead of ) I still wonder if the double `val.replace` are needed, but I am not so good with RegEx so I can't fix ATM. – tomByrer Apr 18 '12 at 06:30
0

custom component in react who receives bold like boolean

{(() => {
  const splitText = theText.split('**');
  return (
    <TextByScale>
      {splitText.map((text, i) => (
        <TextByScale bold={!!(i % 2)}>{text}</TextByScale>
      ))}
    </TextByScale>
  );
})()}
Nicolas Sturm
  • 619
  • 5
  • 7
-1

If you are using jQuery, replace this:

$(document.body).on('click', 'button', function() {

with this:

$("button").click(function () {
Gustavo Gondim
  • 1,635
  • 2
  • 18
  • 39
  • hi Gustavo, thanks for your input, yes I'm using jQuery, the `on` method is a jQuery method starting with 1.7 http://api.jquery.com/on/ that attachs event handlers to the selector in this case the document.body. It is particular useful for elements, such as buttons in this case, which are created dynamically, e.g., by AJAX. – tim peterson Apr 16 '12 at 03:22
  • 3
    thats doesn't really answer the question, does it? – Marty Cortez Apr 16 '12 at 03:22
  • Sorry, it doesn't really answer the question. I missed the document ready too... It looks like your regex it is broken, like the answer below, but the regex below it is broken too. – Gustavo Gondim Apr 16 '12 at 03:32
-1

The following regular expression will find your asterisk-wrapped text:

/\x2a\x2a[A-z0-9]+\x2a\x2a/

I updated your fiddle as an example: http://jsfiddle.net/2LAL4/30/

Marty Cortez
  • 2,325
  • 1
  • 17
  • 22
-2

Your regex is broken, for one thing. You probably want something more like:

/\*\*[A-z0-9]+\*\*/gi

The * is a special character in regular expressions. If you want to match against a literal *, then you need to escape it with \.

For instance: http://jsfiddle.net/2LAL4/22/

However, even with this change there's still a fair ways to go before you get to where you really want to be. For instance, your example will not work if the text area contains a mix of bold and non-bold text.

aroth
  • 54,026
  • 20
  • 135
  • 176
  • hi aroth, thanks, yes I see there is a way to go. It looks like I need to find the asterisk-wrapped text first such that i'm not selecting the entire `textarea.val()`. Would you mind before I stop pestering you more to provide clues on that too? – tim peterson Apr 16 '12 at 03:28
  • If you need one that allows spaces in the bold font: http://jsfiddle.net/2LAL4/172/ – Sean Apr 15 '15 at 14:05
  • `ds**d**d` becomes `dsdsddd`, which is wrong. :( – Benny Code Feb 02 '17 at 14:13