Simple jQuery Solution To A Simple Problem
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.
Interesting take on the code blocks. I’m currently working on a site that will have a lot of code, and I’m planning on using a lightbox-style implementation, but I like the expanding width idea as well.
You could also have used the jQuery Dimensions plugin (which is included in jQuery 1.2.6) and used some of its methods (innerWidth, outerWidth, scrollLeft) to possibly eliminate the need for the additional spans.
re: Dimensions, thanks for the tip, I hadn’t seen that plugin or the news about the integration with 1.2.6. Cool!
If you don’t need the animation, wouldn’t it be enough to set overflow to normal, then on hover set it to visible?
@Thomas yes, I think I’d seen a solution somewhere that did that with CSS. It was a little more fun to animate it, though.
really interesting and useful post!
Thanks you a lot!
That’s really neat.
This comment is a digression from your feature but hope it helps: you could go one step further and wrap it into a plugin using something like this:
$.fn.expandableSyntaxHighlighter = function() {
return $(this).each( function() { /* your code here */ } );
}
Then anyone can use it e.g. $("pre").expandableSyntaxHighlighter();
(In your plugin version, where you reference $("pre"), you’d use $(this), etc.)
Of course, it st even possible for people then to use other elements and you can pass in options too if you want to be fancy.
I really like jQuery and am slowly finding that any solution I make like yours I wrap it into a plugin. If it helps, this is a useful pattern for writing plugins to make them take in options etc:
http://www.learningjquery.com/2007/10/a-plugin-development-pattern
Trackback URL: http://www.viget.com/trackback/1181/
Next entry: Switching Mindsets: From WordPress to ExpressionEngine
Previous entry: Google Now Indexing Flash Content

Recent Comments
Great post. I am in my 8th year with PS, and I am guilty of every one of the ‘bad habits’ you listed. I know all the solutions you mentioned too. It really just must be laziness, or maybe...
- Doug on 'Breaking Bad Habits in Photoshop'.
- Bryan Kulba on 'Breaking Bad Habits in Photoshop'.
- Jon Thomas on 'Resizing rounded rectangles in Photoshop'.
Subscribe to Comments RSS