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
April 22nd, 2009 - 13:29
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
April 23rd, 2009 - 14:05
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
April 28th, 2009 - 10:21
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
April 29th, 2009 - 16:45
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
July 13th, 2009 - 05:20
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…”.
July 13th, 2009 - 10:49
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
July 14th, 2009 - 02:55
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().
August 17th, 2009 - 08:00
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.
August 18th, 2009 - 22:10
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
August 6th, 2009 - 17:09
Groomi, did you notice that in your last comment html was parsed surely this is a security risk
August 6th, 2009 - 17:10
oO it sanitised it for me – maybe its just if you reply through the admin?
August 7th, 2009 - 11:41
o.O