JAVASCRIPT: Add BBCode buttons to a form (REVISITED)

From looking at my visitor logs I can see that the clear favourite page on this site is my [url=http://blog.groomi.net/JAVASCRIPT:_Add_BBCode_buttons_to_a_form-,9]BBCODE Buttons[/url] tutorial. After typing a little comment into a blog on here, I realised that the script still is far from perfect and set about improving it.

The problem I had, was that whenever you inserted a piece of bbcode (wherever in the text you did it) the mouse caret (cursor) would always default back to the end of the textarea (A pain in the ass if you’re typing something before then).

I then set about making some additions + changes to [i]mybbcode_ins()[/i] function.

What I needed to do was:
1. Find the current cursor position
2. Find the length of the text that I will be inserting
3. Add this to the current position
4. Set the mouse position to the new location.

As always, this was a breeze in Firefox and was acheived by changing the lines

[code]var startPos = field.selectionStart;
var endPos = field.selectionEnd;
field.focus();
field.value = field.value.substring(0, startPos)
+ '[' + tag + '='+url+']' + linkText + '[/' + tag+']'
+ field.value.substring(endPos, field.value.length);
[/code]

to

[code]
var startPos = field.selectionStart;
var endPos = field.selectionEnd;
field.focus();
field.value = field.value.substring(0, startPos) + tag + field.value.substring(endPos, field.value.length);
field.setSelectionRange(endPos+tag.length, endPos+tag.length);
[/code]

I used the smilies section of the code to show the change as this is the easiest to understand. Basically, I have done the 4 steps listed above..

This is all done with the line [i]field.setSelectionRange(endPos+tag.length, endPos+tag.length);[/i] which does step 1 (endPos), step 2 (tag.length), step 3 and 4 (setSelectionRange(endPos+tag.length, endPos+tag.length);)

This however is alot more difficult in IE..

Internet Explorer being as dumb as it is doesn’t have a simple way to find the current cursor position. The way it is acheived is by:

1. Making a selection at the current position
2. Moving the selection start to the beginning
3. The cursor location is then the length of your selection
Easy huh?? Not..

What we end up for IE is this

[code]var selected = document.selection.createRange().text;
var ins = tag;
var selected2 = document.selection.createRange();
var sel = document.selection.createRange();
sel.text = tag;
selected2.moveStart ('character', -field.value.length);
sel.moveStart('character', selected2.text.length + ins.length - selected.length);
[/code]
Bloody horrid when compared to the Firefox code, don’t you think??

Well. Most of you have probably read the first tutorial and understood that, and are just after the new code.. I give you, [b]bbcode_ins()[/b]

[code]function bbcode_ins(fieldId, tag)
{
field=document.getElementById(fieldId);
if(tag=='b' || tag=='i' || tag=='u' || tag == 'php' || tag == 'code')
{
if (document.selection)
{
field.focus();
var selected = document.selection.createRange().text;
var ins = '[' + tag + ']' + selected + '[/' + tag +']';
var selected2 = document.selection.createRange();
var sel = document.selection.createRange();
selected2.moveStart ('character', -field.value.length);
sel.text = '[' + tag + ']' + selected + '[/' + tag+']';
sel.moveStart('character', selected2.text.length + ins.length - selected.length);

}

//MOZILLA/NETSCAPE/SAFARI support

else if (field.selectionStart || field.selectionStart == 0)
{
var startPos = field.selectionStart;
var endPos = field.selectionEnd;
var selected = field.value.substring(startPos, endPos);
var ins = '[' + tag + ']' + selected + '[/' + tag +']';
field.focus();
field.value = field.value.substring(0, startPos) + ins + field.value.substring(endPos, field.value.length);
field.setSelectionRange(endPos+ins.length, endPos+ins.length-selected.length);
}
}
else if(tag == 'img')
{
var path = prompt('Enter image path', 'http://');
if(!path)
{
return;
}
if (document.selection)
{
field.focus();
var selected = document.selection.createRange().text;
var ins = '[' + tag + ']' + path + '[/' + tag+']';
var selected2 = document.selection.createRange();
var sel = document.selection.createRange();
sel.text = '[' + tag + ']' + path + '[/' + tag+']';
selected2.moveStart ('character', -field.value.length);
sel.moveStart('character', selected2.text.length + ins.length - selected.length);
}
//MOZILLA/NETSCAPE/SAFARI support
else if (field.selectionStart || field.selectionStart == 0)
{
var startPos = field.selectionStart;
var endPos = field.selectionEnd;
var ins = '[' + tag + ']' + path + '[/' + tag+']';
field.focus();
field.value = field.value.substring(0, startPos)
+ ins
+ field.value.substring(endPos, field.value.length);
field.setSelectionRange(endPos+ins.length, endPos+ins.length-selected.length);
}
}
else if(tag == 'url')
{
var url = prompt('Enter link URL', 'http://');
var linkText = prompt('Enter link text', '');
if(!url || !linkText)
{
return;
}
if (document.selection)
{
field.focus();

var selected = document.selection.createRange().text;
var ins = '[' + tag + '='+url+']' + linkText + '[/' + tag+']';
var selected2 = document.selection.createRange();
var sel = document.selection.createRange();
sel.text = '[' + tag + '='+url+']' + linkText + '[/' + tag+']';
selected2.moveStart ('character', -field.value.length);
sel.moveStart('character', selected2.text.length + ins.length - selected.length);

}
//MOZILLA/NETSCAPE/SAFARI support
else if (field.selectionStart || field.selectionStart == 0)
{
var startPos = field.selectionStart;
var endPos = field.selectionEnd;
var ins = '[' + tag + '='+url+']' + linkText + '[/' + tag+']';
field.focus();
field.value = field.value.substring(0, startPos)
+ ins
+ field.value.substring(endPos, field.value.length);
field.setSelectionRange(endPos+ins.length, endPos+ins.length-selected.length);
}
}
else //For smilies
{
if (document.selection)
{
field.focus();

var selected = document.selection.createRange().text;
var ins = tag;
var selected2 = document.selection.createRange();
var sel = document.selection.createRange();
sel.text = tag;
selected2.moveStart ('character', -field.value.length);
sel.moveStart('character', selected2.text.length + ins.length - selected.length);
}

//MOZILLA/NETSCAPE/SAFARI support

else if (field.selectionStart || field.selectionStart == 0)
{
var startPos = field.selectionStart;
var endPos = field.selectionEnd;
field.focus();
field.value = field.value.substring(0, startPos) + tag + field.value.substring(endPos, field.value.length);
field.setSelectionRange(endPos+tag.length, endPos+tag.length);
}
}
}[/code]

I am also considering having the caret sit between the two tags. This will be a simple subtraction of 4 from the length added to the current position.

Please don’t be afraid to comment or ask questions below as we have lots of people viewing the site but very few contributing. Please drop me a comment telling me wether you hate me, appreciated my code, want to hire me for work :wave: etc etc. I don’t bite, and will probably write some new code if I see that mine is being appreciated :)

Much Love
Stephen

  • Share/Bookmark

12 Comments

  • By Scott, April 22, 2009 @ 1:29 pm

    Hi! Great piece of code. I was looking at this about a week ago, and you had a working example up. (Nice makeover by the way) Do you have a working example I can find somewhere? I’m working on an online application for musicians, and need to be able to insert tags into a song file, and this will probably fit the bill quite nicely.

    Thanks,
    Scott

  • By Stephen Groom, April 23, 2009 @ 2:05 pm

    Hey Scott,

    If you are referring to the code that WAS here (http://blog.groomi.net/inc/javascript/bbcode.js) which was a static .js file, here it is:

    function bbcode_ins(fieldId, tag)
    {
    field=document.getElementById(fieldId);
    if(tag==’b’ || tag==’i’ || tag==’u’ || tag == ‘php’ || tag == ‘code’)
    {
    if (document.selection)
    {
    field.focus();
    var selected = document.selection.createRange().text;
    var ins = ‘[' + tag + ']‘ + selected + ‘[/' + tag +']‘;
    var selected2 = document.selection.createRange();
    var sel = document.selection.createRange();
    selected2.moveStart (‘character’, -field.value.length);
    sel.text = ‘[' + tag + ']‘ + selected + ‘[/' + tag+']‘;
    sel.moveStart(‘character’, selected2.text.length + ins.length – selected.length – 4);

    }

    //MOZILLA/NETSCAPE/SAFARI support

    else if (field.selectionStart || field.selectionStart == 0)
    {
    var startPos = field.selectionStart;
    var endPos = field.selectionEnd;
    var selected = field.value.substring(startPos, endPos);
    var ins = ‘[' + tag + ']‘ + selected + ‘[/' + tag +']‘;
    field.focus();
    field.value = field.value.substring(0, startPos) + ins + field.value.substring(endPos, field.value.length);
    field.setSelectionRange(endPos+ins.length, endPos+ins.length-selected.length – 4);
    }
    }
    else if(tag == ‘img’)
    {
    var path = prompt(‘Enter image path’, ‘http://’);
    if(!path)
    {
    return;
    }
    if (document.selection)
    {
    field.focus();
    var selected = document.selection.createRange().text;
    var ins = ‘[' + tag + ']‘ + path + ‘[/' + tag+']‘;
    var selected2 = document.selection.createRange();
    var sel = document.selection.createRange();
    sel.text = ‘[' + tag + ']‘ + path + ‘[/' + tag+']‘;
    selected2.moveStart (‘character’, -field.value.length);
    sel.moveStart(‘character’, selected2.text.length + ins.length – selected.length);
    }
    //MOZILLA/NETSCAPE/SAFARI support
    else if (field.selectionStart || field.selectionStart == 0)
    {
    var startPos = field.selectionStart;
    var endPos = field.selectionEnd;
    var ins = ‘[' + tag + ']‘ + path + ‘[/' + tag+']‘;
    field.focus();
    field.value = field.value.substring(0, startPos)
    + ins
    + field.value.substring(endPos, field.value.length);
    field.setSelectionRange(endPos+ins.length, endPos+ins.length-selected.length);
    }
    }
    else if(tag == ‘url’)
    {
    var url = prompt(‘Enter link URL’, ‘http://’);
    var linkText = prompt(‘Enter link text’, ”);
    if(!url || !linkText)
    {
    return;
    }
    if (document.selection)
    {
    field.focus();

    var selected = document.selection.createRange().text;
    var ins = ‘[' + tag + '='+url+']‘ + linkText + ‘[/' + tag+']‘;
    var selected2 = document.selection.createRange();
    var sel = document.selection.createRange();
    sel.text = ‘[' + tag + '='+url+']‘ + linkText + ‘[/' + tag+']‘;
    selected2.moveStart (‘character’, -field.value.length);
    sel.moveStart(‘character’, selected2.text.length + ins.length – selected.length);

    }
    //MOZILLA/NETSCAPE/SAFARI support
    else if (field.selectionStart || field.selectionStart == 0)
    {
    var startPos = field.selectionStart;
    var endPos = field.selectionEnd;
    var ins = ‘[' + tag + '='+url+']‘ + linkText + ‘[/' + tag+']‘;
    field.focus();
    field.value = field.value.substring(0, startPos)
    + ins
    + field.value.substring(endPos, field.value.length);
    field.setSelectionRange(endPos+ins.length, endPos+ins.length-selected.length);
    }
    }
    else //For smilies
    {
    if (document.selection)
    {
    field.focus();

    var selected = document.selection.createRange().text;
    var ins = tag;
    var selected2 = document.selection.createRange();
    var sel = document.selection.createRange();
    sel.text = tag;
    selected2.moveStart (‘character’, -field.value.length);
    sel.moveStart(‘character’, selected2.text.length + ins.length – selected.length);
    }

    //MOZILLA/NETSCAPE/SAFARI support

    else if (field.selectionStart || field.selectionStart == 0)
    {
    var startPos = field.selectionStart;
    var endPos = field.selectionEnd;
    field.focus();
    field.value = field.value.substring(0, startPos) + tag + field.value.substring(endPos, field.value.length);
    field.setSelectionRange(endPos+tag.length, endPos+tag.length);
    }
    }
    }

    If you are referring to one which was in the comments below the post, I cannot find anything obvious right now (I only had a quick look) but I will continue to look if this is not right.

    I am also at some point in the near future going to look into adding a [code] tag to wordpress to tidy up some of my older posts such as this one.

    Thanks
    Stephen

    PS. You might get lucky searching for 'cache:groomi.net' in google search

  • By Tim, April 28, 2009 @ 10:21 am

    Hi Stephen!

    Nice tutorial! The only thing: I cant get it to work :$ could you please explain to me how i can do it?

    ATM I have a onclick event on a tag: bold

    where bericht = the id of the textarea
    and b = bold tag?

    Thanks!
    Tim

  • By Stephen Groom, April 29, 2009 @ 4:45 pm

    Hey..

    Your comment was filtered I think.

    Send me an email groomi [[at§]] groomi dot net with the problem and I’ll post it up here :)

    Cheers

  • By Matthew C, July 13, 2009 @ 5:20 am

    It works well in IE 7, but in Firefox 3.5 I get a “field is null” error in the Error Console.

    Any fix? I just used your JavaScript (the IMG and URL prompt text), edited it a bit and gave you a line saying “Source from Groomi…”.

  • By Stephen Groom, July 13, 2009 @ 10:49 am

    Cool, Credit is good :)

    Er.. re: the error, it was never tested with firefox 3 IIRC, just 2 and safari etc etc

    The only thing that I could suggest that would trigger a “field” error is if you call the function wrong. Remember, it is bbcode_ins(“fieldId”, “tag”) which would refer to

    If you can find me a link to the page where you are using it I will do a little bit of investigation :)

    Thanks

  • By Matthew C, July 14, 2009 @ 2:55 am

    Sure, I’ll pop you a email. I know it works on Firefox 3.0, just not v3.5.. Heh.

    I also renamed the function to smileyinsert().

  • By Craig, August 6, 2009 @ 5:09 pm

    Groomi, did you notice that in your last comment html was parsed surely this is a security risk :)

  • By Craig, August 6, 2009 @ 5:10 pm

    oO it sanitised it for me – maybe its just if you reply through the admin?

  • By Stephen Groom, August 7, 2009 @ 11:41 am

    o.O :)

  • By Matthew C, August 17, 2009 @ 8:00 am

    Hey Stephen,

    Like I said, I got the JavaScript that’s not playing nice with Firefox 3.5 on my site, which is located if you click my comment’s author text.

    You’ll need to register (sorry!), the BBCode toolbar is visible on News Comment pages, forum threads and new thread pages.

    I hope you can identify the issue.

  • By Stephen Groom, August 18, 2009 @ 10:10 pm

    Hi Matthew,

    As I am using MacOS now, I do not have firefox installed so will not be able to replicate the problem.

    Could you paste here any errors you receive in Firefox’s error console and I will look at your source and try to resolve them
    Thanks

Other Links to this Post

RSS feed for comments on this post. TrackBack URI

Leave a comment

WordPress Themes