beautyOfCode: jQuery Plugin for Syntax Highlighting

UPDATE: Support for Syntax Highlighter 2.0 + jQuery Listed + bitbucket Repository

The Syntaxhighlighter by Alex Gorbatchev is the best I have seen so far. As you see in this post, wordpress.com uses it, too.

But the required syntax is not xhtml-compliant (name on pre is forbidden).

<pre name="code" class="javascript">
  // my code
</pre>

In order to enable compliant xhtml I had to rewrite a small part anyway, so I just made a small jQuery-Plugin that just uses Alex’s scripts right away (thanks Alex!).

Beautify explicitely

<pre id="myCode">
  <code>
     // my code
  </code>
</pre>

Using beautyOfCode you don’t have to decorate your html in order to enable syntax highlighting. Just call beautifyCode on any selected pre or textarea

$(function(){
    $.beautyOfCode.init('clipboard.swf');
    $("#myCode").beautifyCode('javascript');
});

Beautify all

If you prefer to decorate your html and then just let the highlighter take care of the rest, you may use following notation.

<pre class="code">
  <code class="javascript">
     // my code
  </code>
</pre>

<pre class="code">
  <code class="css boc-nocontrols">
    body {
      font-size: 2em;
    }
  </code>
</pre>

Make sure you have these few lines

$(function(){
    $.beautyOfCode.init('clipboard.swf');
    $.beautyOfCode.beautifyAll();
});

Settings

Default Settings

{
   noGutter: false, // hide line numbers?
   addControls: true, // copy, view plain, ...
   collapse: false, // show controls with expand link
   showColumns: false, // show column numbers
   firstLine: 1 // start with another line number?
}

Change Settings with Javascript

$(function(){
  $.beautyOfCode.init('clipboard.swf', {
    // add global settings here
    firstLine: 4,
    collapse: true
  });

  // change options per listing
  $("#myCode").beautifyCode('javascript', {
    noGutter: true
  });
});

Change Settings in Element-Decoration

Settings with in the html are added as additional classes on the code-element.

<pre class="code">
  <!-- You dont have to specify default values. -->
  <code class="javascript boc-firstline&#91;3&#93;
    boc-nocontrols
    boc-nogutter
    boc-showcolumns
    boc-collapse">
     // my code
  </code>
</pre>

kick it on DotNetKicks.com

Source Code

Notice: beautyOfCode is using Syntaxhighlighter. You need to link in SyntaxHighlighter.css, shCore.js and the brushes you want to use.

jQuery.beautyOfCode = {
  initialized: false,

  settings: {

    // hide line numbers?
    noGutter: false,

    // show copy, plain, ... links
    addControls: true,

    // collapse to control bar. cant be used
    // with addControls set to false
    collapse: false,

    // show column numbers
    showColumns: false,

    // start with another line number?
    firstLine: 1
  },

  brushByAlias: {},

  init: function (clipboardSwf, settings) {
    dp.SyntaxHighlighter.ClipboardSwf = clipboardSwf;

    if (settings)
      jQuery.extend(jQuery.beautyOfCode.settings, settings);

    if (jQuery.beautyOfCode.isInitialized)
      return;

    // creates a map of each registered brush by alias
    jQuery.each(dp.sh.Brushes, function (i, brush) {
      var aliases = brush.Aliases;

      if(aliases == null)
       return;

      jQuery.each(aliases, function (ii, alias) {
        jQuery.beautyOfCode.brushByAlias[alias] = brush;
      });
    });

    jQuery.beautyOfCode.isInitialized = true;
  },

  addCssForBrush: function (brush, highlighter) {
    if (brush.isCssInitialized)
      return;

    var headNode = $("head")[0];
    if(highlighter.Style && headNode)
    {
      var styleNode = document.createElement('style');
      styleNode.setAttribute('type', 'text/css');

      if(styleNode.styleSheet) // for IE
        styleNode.styleSheet.cssText = highlighter.Style;
      else // for everyone else
        $(styleNode).text(highlighter.Style);

      headNode.appendChild(styleNode);
    }

    brush.isCssInitialized = true;
  },

  beautifyAll: function() {
    jQuery("pre.code:has(code[class])").each(function (i, item) {

      function getOptionValue(name, list)
      {
        var regex = new RegExp('^' + name + '\\[(\\w+)\\]$', 'gi');
        var matches = null;

        for(var i = 0; i < list.length; i++)
         if((matches = regex.exec(list[i])) != null)
          return matches[1];

        return null;
      }

      var $item = jQuery(item);
      var $code = $item.children("code");
      var code = $code[0];

      var options = code.className.split(" ");
      var language = options[0];

      var settings = {};

      if ($code.hasClass("boc-nogutter"))
        settings.noGutter = true;

      if ($code.hasClass("boc-nocontrols"))
        settings.addControls = false;

      if ($code.hasClass("boc-showcolumns"))
        settings.showColumns = true;

      if ($code.hasClass("boc-collapse"))
        settings.collapse = true;        

      var firstLine = getOptionValue("boc-firstline", options, 1);
      if (firstLine)
        settings.firstLine = firstLine;

      $item.beautifyCode(language, settings);
    });
  }
};

jQuery.fn.beautifyCode = function (language, settings) {

  var saveLanguage = language;
  var saveSettings = settings;

  // iterate all elements
  this.each( function (i, item) {
    var $item = jQuery(item);

    var settings = jQuery.extend({}, jQuery.beautyOfCode.settings, saveSettings);

    var brush = jQuery.beautyOfCode.brushByAlias[saveLanguage];

    if (!brush)
      return;

    // instantiate brush
    highlighter = new brush();

    // set brush options
    jQuery.extend(highlighter, settings);

    jQuery.beautyOfCode.addCssForBrush(brush, highlighter);

    // IE Bug?: code in pre has to be skipped
    // in order to preserver line breaks.
    if ($item.is("pre") && ($code = $item.children("code")))
      $item.text($code.text());

    highlighter.Highlight($item.html());
    highlighter.source = item;

    $item.replaceWith(highlighter.div);
  });
}
[/sourcecode]