Simple jQuery Solution To A Simple Problem

Doug Avery, Former Senior Developer

Article Category: #Design & Content

Posted on

When building out the Viget Extend blog, I really wanted to give some special attention to the real meat of the content: the code blocks.

After looking at some other dev blogs, it seemed like there were two types: Big Ol' Blocks and Little Snippets. The big ones deserved the full treatment: Scrollbars, full colorization, line-numbering, all of it. We accomplished this with SyntaxHighlighter, a cool JS file that handles all this work. The developers just need to slap a name="code" on their pre tags, and SyntaxHighlighter formats and colors everything properly. (View an example of the treatment)

The shorter code snips were a little trickier. We didn't want them to linebreak automatically (like code here at Inspire does) for accuracy reasons, but we didn't want to apply scrollbars to something as simple as a single line of code. The solution was a quick jQuery idea: Expanding the code block on hover, so they grow to the full width of the page.

 $("pre").hover(function() { $(this).animate({ width: "765px"}, 250); }, function() { $(this).animate({ width: "437px" }, 250); }); 

This was all right for a while, but soon we began running into posts like this one, where one or more of the blocks just didn't need the expanding treatment. In these cases, the jQuery effect was just annoying.

For a while, I just let it be, but this morning the answer hit me: We could probably do something to get the width of the code block's contents, and trigger the effect based on whether not the content width exceeded the block's. The first part was just setting up a variable to get the widths of both the block and the block's contents:

var contentwidth = $(this).contents().width(); var blockwidth = $(this).width();

But this isn't quite enough, because the "contents" traversal method needs a definite element to grab, and the pre tags only contained plain text. We needed to add an inline element to wrap the text:

$("pre").wrapInner("<span></span>");

This wraps the inside of pre tags with spans, but adds a problem: Now we've got errant spans showing up in our bigger, SyntaxHighlighted blocks. So we need a quick selector fix:

$("pre:not([name='code'])").wrapInner("<span></span>");

All better. The last step is to put it all together, and add the if statement that's going to test whether the block expands or not:

 $("pre:not([name='code'])").wrapInner("<span></span>"); $("pre").hover(function() { var contentwidth = $(this).contents().width(); var blockwidth = $(this).width(); if(contentwidth > blockwidth) { $(this).animate({ width: "765px"}, 250); } }, function() { $(this).animate({ width: "437px" }, 250); }); 
For an example of the finished effect, and the width discrimination, see Testing For HTML Tags in Rails Plugins.

Related Articles