Publishing System Settings Logout Login Register
Building Better BBCode
TutorialCommentsThe AuthorReport Tutorial
Tutorial Avatar
Rating
Add to Favorites
Posted on August 3rd, 2008
6128 views
JavaScript
Building Better BBCode


BBCode is an abbreviation for Bulletin Board Code, the lightweight markup language used to format posts in many message boards. It is also called forum codes. The available tags are usually indicated by rectangular brackets surrounding a keyword, and they are parsed by the message board system before being translated into a markup language that web browsers understand, usually HTML or XHTML.


This tutorial demonstrates how to parse bbcode using php and regex, insert bbcode at the position of the caret, or, in the case that a block of text is selected, wrap the bbcode around that text in a cross-browser compatible way.
A live (fully functional, but not pretty. That's up to you) is here: Live Demo

Basically, BBCode is used for formatting messages. (HTML for the average user, I guess) BBCode typically handles simple formatting, bold/underlined/italicized text, links and images, quotes, et cetera.

Note:
This tutorial is recommended for those who have a basic understanding of php, javascript, and a general knowledge of regex. This tutorial will NOT hold your hand and walk you through anything other than inserting bbcode tags into a text box at the position of the caret, and then using simple regex to format them for storage.

There are two steps to creating a working bbcode system for integration into your guestbook/forum/whatever.
The first is the backend, which uses regex to match bbcode and change it to html.




bbcode.php

[code]
<?php
/*
*------------------------------------------------------------------------------
*   BBCode Tutorial
*
*------------------------------------------------------------------------------
*   Bbcode encoding for text formatting
*   Derived from: http://www.swaziboy.com/web development/php/index.php
*/

    function bb_encode($Text) {
       
       
        $Text = str_replace("<", "<", $Text);
        $Text = str_replace(">", ">", $Text);
       
        //new lines
        $Text = nl2br($Text);
       
        //        
        $Text = preg_replace("/[url]([$URLSearchString]*)" target="_blank">
        $URLSearchString = " a-zA-Z0-9:/-?&.=_~#'";
       
        $Text = preg_replace("/[url]([$URLSearchString]*)
/", '<a href="$1" target="_blank">$1</a>', $Text);
        $Text = preg_replace("(*)](.+?))", '<a href="$1" target="_blank">$2</a>', $Text);
       
        // [b]
        $Text = preg_replace("((.+?))is",'<strong>$1</strong>',$Text);
       
        // [i]
        $Text = preg_replace("((.+?))is",'<em>$1</em>',$Text);
       
        // [u]
        $Text = preg_replace("((.+?))is",'<u>$1</u>',$Text);
       
        // [s]
        $Text = preg_replace("([s](.+?)[/s])is",'<del>$1</del>',$Text);
       
        // [center]
        $Text = preg_replace("([center](.+?)[/center])is",'<div align="center">$1</div>',$Text);
       
        // [color]
        $Text = preg_replace("((.+?))is","<span style="color: $1">$2</span>",$Text);
       
        // [size]
        $Text = preg_replace("([size=(.+?)](.+?)[/size])is","<span style="font-size: $1px">$2</span>",$Text);
       
        // [quote]
        $QuoteLayout = '<table width="90%" border="0" align="center" cellpadding="0" cellspacing="0">
                            <tr>
                                <td class="codehead"> $1 wrote:</td>
                            </tr>
                            <tr>
                                <td class="quotebody">$2</td>
                            </tr>
                       </table>';
       
        $QuoteLayoutAnon = '<table width="90%" border="0" align="center" cellpadding="0" cellspacing="0">
                            <tr>
                                <td class="codehead">Quote:</td>
                            </tr>
                            <tr>
                                <td class="quotebody">$2</td>
                            </tr>
                       </table>';
                      
                
        $Text = preg_replace("/[quote](.+?)[/quote]/is","$QuoteLayoutAnon", $Text);
        $Text = preg_replace("/[quote=(.+?)](.+?)[/quote]/is","$QuoteLayout", $Text);
       
        // [img]
        $Text = preg_replace("/[img](.+?)[/img]/", '<img src="$1">', $Text);
           
        // [youtube]
        $youtubeformatting = '<object width="425" height="355"><param name="movie" value="$1"></param><param name="wmode" value="transparent"></param><embed src="$1&hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object>';
        $Text = preg_replace("/[youtube](.+?)[/youtube]/", '$youtubeformatting', $Text);
           
       
        return $Text;
    }
   
?>
[/code]


The above code changes the user's input from bbcode into html for storage in a database (or whatever else you are planning on using it for). (e.g.
Bold Text
is turned into
<strong>Bold Text</strong>
) What happens if the user wants to edit their post? Well, there are two ways to go about that. The lazy way, and the nice way. Being a lazy person myself, I use the first when I can get away with it :)

Lazy Method
In the database, make two columns, one for post_formatted, and one for post_raw. Post_raw is the data that doesn't pass through the bb_encode function, which still has the unparsed bbcode tags. When the user wants to edit or another user quotes them (assuming you're implementing this in a guestbook/forum type system), retrieve post_raw, and then when they want to view, retrieve post_formatted.

Nice Method
Create a bb_decode function. Basically reverse everything in the above code to get the data from nice, formatted, html, to messy bbcode. Quite simply, all you need to do is reverse the arguments in the preg-replace functions. Neither of the above storage methods will be covered in this tutorial, that's up to you to figure out.


The Javascript
The main highlight of this tutorial is the ability to insert bbcode at the caret position, and then to wrap it around text if text is selected.

This javascript was derived from some other bbcode tutorial that I can't seem to find at the moment. Though, the main point of this tutorial is to insert at the caret position, or wrap the tags around a block of selected text, the tutorial where I originally based this from did neither. If you can find where this came from, would you please link to it and I'll include due credit?


<script type="text/javascript">
//bbcode insertion..

//define tags, to let the script know when a tag is open and needs to be closed
var b = 2;
var i = 2;
var u = 2;
var s = 2;
var q = 2;
var center = 2;
var url = 2;
var img = 2;
var youtube = 2;

//function to insert tags
function tag(v, tagadd, newbut, tagclose, oldbut, name) {
    //our text box
    var txt = window.document.posting.post;
   
    //ie handles selections differently
    if (document.selection) {
   
        //if text is selected, wrap the tags
        theSelection = document.selection.createRange().text;
        if (theSelection) {

        document.selection.createRange().text = tagadd + theSelection + tagclose;
        txt.focus();
        theSelection = '';
        }
        else{
       
        //if there are no open tags of this type, open one
        if (eval(v)%2 == 0) {
         document.getElementById(name).value = newbut;
        txt.focus();
        sel = document.selection.createRange();
        sel.text = tagadd;
    } else {
   
        //otherwise, close the tag
        document.getElementById(name).value = oldbut;
        txt.focus();
        sel = document.selection.createRange();
        sel.text = tagclose;
    }
    }
    //add to the total number of tags, if the tag just added was an opening tag, the number will be odd and the script will know to close it next time
    eval(v+"++;");
        }

//firefox time =)
else{

    //if text is selected, wrap the tags
    if((txt.value).substring(txt.selectionStart, txt.selectionEnd) != ''){
           txt.value = (txt.value).substring(0, txt.selectionStart) + tagadd + (txt.value).substring(txt.selectionStart, txt.selectionEnd) + tagclose + (txt.value).substring(txt.selectionEnd, txt.textLength);
        return;
        }
        else{
    //if there are no open tags of this type, open one
    if (eval(v)%2 == 0) {
         document.getElementById(name).value = newbut;
        txt.value = (txt.value).substring(0, txt.selectionStart) + tagadd + (txt.value).substring(txt.selectionEnd, txt.textLength);
        txt.focus();
       
    //otherwise, close the tag
    } else {
        document.getElementById(name).value = oldbut;
        txt.value = (txt.value).substring(0, txt.selectionStart) + tagclose + (txt.value).substring(txt.selectionEnd, txt.textLength);
        txt.focus();
    }
    //same as with ie
    eval(v+"++;");
    }
}
}
//handles font size and color
function font(bbopen, bbclose) {
        var txt = window.document.posting.post;
        //simply add it on to the end of the form
        txt.value += bbopen + bbclose;
        txt.focus();
        return;
}

//a little help text line underneath the bbcode buttons detailing their syntax, et cetera. (phpbb style)
bold_help = "Bold text: text";
italic_help = "Italic text: text";
underline_help = "Underline text: text";
strikethrough_help = "Strikethrough: [s]text[/s]";
center_help = "Center Text: [center]text[/center]";
quote_help = "Quote text: [quote]text[/quote] or [quote=name]text[/quote]";
img_help = "Insert image: [img]http://image_url[/img]";
url_help = "Insert URL: http://url or URL text";
youtube_help = "Embed Youtube Video: [youtube]http://youtube.com/watch?v=video_id[/youtube]";
fontcolor_help = "Font color: text  Tip: you can also use color=#FF0000";
fontsize_help = "Font size: [size=7]small text[/size]";

function helpline(help) {
        var helpbox = document.getElementById('helpbox');
        helpbox.value = eval(help + "_help");
}
</script>


The above javascript is compatible in both IE and Firefox, and as such, probably in Opera. Not sure about Safari, though =(
It should be fairly self explanatory, and can be stored in an external javascript file and included on your page to keep everything clean, if you would prefer it.




The HTML
The html file just stores all of the buttons, the helpline, and the textarea. Not all that much to it.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Building Better BBCode :: HTML</title>
</head>

<body>
<form name="posting" id="posting" method="post" action="">
    <input type="button" class="button" value="Bold" id="bold" name="bold" onClick="tag('b', '', 'Bold*', '', 'Bold', 'bold');" onMouseOver="helpline('bold')" />
<input type="button" class="button" value="Italic" name="italic" id="italic" onClick="tag('i', '', 'Italic*', '', 'Italic', 'italic');" onMouseOver="helpline('italic')" />
<input type="button" class="button" value="Underline" name="underline" id="underline" onClick="tag('u', '', 'Underline*', '', 'Underline', 'underline');" onMouseOver="helpline('underline')" />
<input type="button" class="button" value="Strikethrough" name="strikethrough" id="strikethrough" onClick="tag('s', '[s]', 'Strikethrough*', '[/s]', 'Strikethrough', 'strikethrough');" onMouseOver="helpline('strikethrough')" />
<input type="button" class="button" value="Center" name="center" id="center" onClick="tag('center', '[center]', 'Center*', '[/center]', 'Center', 'center');" onMouseOver="helpline('center')" />
<input type="button" class="button" value="Quote" name="quote" id="quote" onClick="tag('q', '[quote]', 'Quote*', '[/quote]', 'Quote', 'quote');" onMouseOver="helpline('quote')" />
<input type="button" class="button" value="Url" name="url" id="url" onClick="tag('url', '', 'Url*', '', 'Url', 'url');" onMouseOver="helpline('url')" />
<input type="button" class="button" value="Img" name="img" id="img" onClick="tag('img', '[img]', 'Img*', '[/img]', 'Img', 'img');" onMouseOver="helpline('img')" />
<input type="button" class="button" value="Youtube" name="youtube" id="youtube" onClick="tag('youtube', '[youtube]', 'Youtube*', '[/youtube]', 'Youtube', 'youtube');" onMouseOver="helpline('youtube')" />
<br />
Font size: <select name="fontsize" onChange="font('[size=' + this.form.fontsize.options[this.form.fontsize.selectedIndex].value + ']', '[/size]');" onMouseOver="helpline('fontsize')" class="form_elements_dropdown">
    <option value="7" >Tiny</option>
    <option value="9" >Small</option>
    <option value="18" >Large</option>
    <option  value="24" >Huge</option>
</select>

Font color: <select name="fontcolor" onChange="font('.value + ']', ''); this.selectedIndex=0;" onMouseOver="helpline('fontcolor')" class="form_elements_dropdown"  >
    <option value="black" style="color:black">Black</option>
    <option value="silver" style="color:silver">Silver</option>
    <option value="gray" style="color:gray">Gray</option>
    <option value="maroon" style="color:maroon">Maroon</option>
    <option value="red" style="color:red">Red</option>                                                                               
    <option value="purple" style="color:purple">Purple</option>
    <option value="fuchsia" style="color:fuchsia">Fuchsia</option>
    <option value="navy" style="color:navy">Navy</option>
    <option value="blue" style="color:blue">Blue</option>
    <option value="aqua" style="color:aqua">Aqua</option>
    <option value="teal" style="color:teal">Teal</option>
    <option value="lime" style="color:lime">Lime</option>
    <option value="green" style="color:green">Green</option>
    <option value="olive" style="color:olive">Olive</option>
    <option value="yellow" style="color:yellow">Yellow</option>
    <option value="white" style="color:white">White</option>
</select>
<br />
<input type="text" name="helpbox" id="helpbox" size="100" class="helpbox" readonly="readonly"/>
<hr />
<textarea name="post" cols="75" rows="25"></textarea>
<input type="submit" value="Post!" name="post" />
</form>
</body>
</html>




Conclusion
This tutorial tackles one of the harder problems with things like bbcode, that problem being: inserting formatting at the location of the caret. The majority of the script should be fairly self explanatory. Good luck!
Dig this tutorial?
Thank the author by sending him a few P2L credits!

Send
Errdoth

This author is too busy writing tutorials instead of writing a personal profile!
View Full Profile Add as Friend Send PM
Pixel2Life Home Advanced Search Search Tutorial Index Publish Tutorials Community Forums Web Hosting P2L On Facebook P2L On Twitter P2L Feeds Tutorial Index Publish Tutorials Community Forums Web Hosting P2L On Facebook P2L On Twitter P2L Feeds Pixel2life Homepage Submit a Tutorial Publish a Tutorial Join our Forums P2L Marketplace Advertise on P2L P2L Website Hosting Help and FAQ Topsites Link Exchange P2L RSS Feeds P2L Sitemap Contact Us Privacy Statement Legal P2L Facebook Fanpage Follow us on Twitter P2L Studios Portal P2L Website Hosting Back to Top