Sunday, 18 February 2007

Javascript code viewer

A few people have told me they love the way I have provided syntax highlighting (discussed here but hate the way it wraps around long lines of code.

So I have partially fixed this (I havnt changed the layout - I quite like it and it would take me forever now to change the template after all the tweaks I have made to it!). The solution I have created is a half way house. Now when you click on some code a little viewer pops up and will not allow the text to wrap around, for example:

A very very very very very very very very very very very very very very very very very very very very very very very very very long line of code
and a not very long line of code
This was achieved with some quite neat Javascript and css (err.. apart from the table in there, but lets ignore that). The panel which displays the code looks like this:-

<div id='float' style='display:none; Position:Absolute; background: white; border: solid #4682B4 2px; z-index:100;'>

<table cellspacing=0>
<tr onMouseDown='HideThis();' style='cursor:hand; background: #4682B4;padding: 2px 2px 2px 2px;'>
<td style='text-align:left'>
<b>Code Viewer</b>
<td style='text-align:right'>
<img src=''/>
<td colspan="1">
<div class="csharpcode" id='FloatContent' style='padding: 10px 10px 10px 10px;display:block; text-align:left'>
The blank div tag with the id "FloatContent" is where I will eventually stick the html formatted code the user clicks on. Notice how it has the class csharpcode. This is because i formatted the code using manoli code formatter, and that class provides all the syntax highlighting.

To make it all hang together all that is needed is to add this javascript:

function ShowThis(x)
var coors = findPos(x);
var oFloat = document.getElementById('float');
var oFloatContent = document.getElementById('FloatContent'); = ''; = coors[1] + 'px'; = coors[0] + 'px';
oFloatContent.innerHTML = x.innerHTML;
function HideThis()
document.getElementById('float').style.display = 'none';
function findPos(obj) {
var curleft = curtop = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft
curtop = obj.offsetTop
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft
curtop += obj.offsetTop
return [curleft,curtop];
(The findPos function was taken from here)

This code simply moves the div to the position of the calling element, and copies the html from it to the div, then it makes the div visible! Easy:)

Now all we have to do is add an onclick event to the pre tag around every piece of syntax highlighted code like:

onClick='ShowThis( this)'
Well not quite - thats a rubbish solution having to add that to every piece of syntax highlighted code - I was once told you should only ever have to do something once, if you need to do it more than that - script it (yes he was a bit of a geek!).

So I wrote some javascript to basically parse the page and add the onclick event for me (plus a tool tip to tell people to click it, and I change the cursor to "hand" to make it obvious to click)
function AddHandler()
var links = document.getElementsByTagName('pre');
for(var i = 0; i < links.length; ++i) {
var MyPre = links[i];
MyPre.onclick= function(){ ShowThis( this)};
MyPre.title="Click to view the code";"hand";
As you can see it uses the keyword "function" to dynamically add the on click event for me, and it uses get elements by tag name to find all my code tags! (it validates that the pre section is actually code by checking the class name as well).

The only issue I have is with IE. Firefox does not have this issue (annoyingly, I only use IE 7 normally!). The problem is that innerHTML does not pass through white space, and obviously innerText wont pass through the html encoded syntax highlighting. As a result everything appears without tab indentation. Not quite sure how to fix this just yet, but hopefully somebody cleverer than me at Waterstons will be able to fix it!



1 comment:

Powlo said...

That's very cool.