Highlight text using jQuery and the HTML5 mark tag

Here’s a jQuery plugin I wrote that’ll add HTML5 <mark> tags around keywords or phrases in an element’s body text.

What is mark?

a run of text in one document marked or highlighted for reference purposes, due to its relevance in another context

http://www.whatwg.org/specs/web-apps/

Usage

Add the script to your page, and then when the DOM is ready, do something like:

    $('body').mark('Lorem ipsum');

The plugin can actually be used to wrap any tag around keywords. Simply pass the tag name you want to use as an option:

    $('body').mark({
      text: 'Lorem ipsum',
      tag:  'span',
      cssClass:  'mark'
    });

The above example will wrap span elements around the words lorem and ipsum. Each span element will have the class ‘mark’. View an example implementation.

TODO

  1. Input sanitation on the text to be marked. Currently the text is dumped straight into a regular expression. It needs to be escaped so that any regular expression meta-characters are interpreted as literals.
  2. Similarly, HTML special characters in the input need to be expanded into their HTML entities.
  3. From what I can see, IE doesn’t like <mark> tags, and seems to automatically self close the opening and closing tags inserted into the DOM. WTF? Can anyone shed any light on this problem? For now, you’re going to have to use a <span> with a CSS class

If you’re interested in contributing, get in touch

Using HTML5 canvas.toDataURL to generate placeholder images

A while ago lewis had a great idea – an online tool to figure out the proportional height, when given a width and a particular proportion.

I’ve actually needed to use it 3 or 4 times since it was created around a month ago, so I was keen to get involved and implement some of the suggestions he received to make it better. One of the suggestions was that the tool should generate placeholder graphics, which developers can use whilst creating websites.

I was thinking PHP GD library, which could have quite easily have done the job. However, there are a few disadvantages with this:

  1. The user has to wait while the browser makes a request to the server and gets the response
  2. The server has to have the GD image library installed!
  3. The server has to do work to generate images – eating up your valuable CPU cycles
  4. The server has to temporarily store the generated image – using up disk space
  5. The request and response both use up bandwidth
  6. The tool wouldn’t work offline

All of which could be argued to be relatively inconsequential…but I wanted to do something fun. I decided to use the HTML5 canvas element to draw the placeholder graphic because, well, that sounded fun.

Canvas has a method called "toDataURL" which (as you can probably guess) encodes the content of the canvas as a data url. I spent a couple of hours in the evening knocking up a prototype utilising this functionality.

You may be thinking (when looking at the source for the prototype): "where’s the canvas"? What actually happens is that when you change the width or height using the input boxes, the page dynamically creates a canvas element, draws the placeholder graphic inside, calls toDataURL and then creates an <img> tag, whose "src" attribute is set the data url we got from the canvas. The page then removes the canvas element and the old placeholder graphic, and appends the new graphic to the DOM. The process is so fast you don’t ever see the canvas element on the page.

The reason we don’t just leave the canvas on the page is because we want users to be able to save these graphics. You can’t right click on a canvas and select "Save image as…".

The only disadvantage I can think of by using this method is that it won’t work on older browsers…or browsers without javascript enabled. Ok that is two. Other than that, it’s great:

  1. The user doesn’t have to wait for a round trip to the server to complete
  2. The server does no further work other than to serve the script file
  3. No bandwidth is consumed transferring the image
  4. The tool even works offline!

To me, that sounds like WIN.

iframe automatic height adjustment using HTML5 cross domain web messaging

Yesterday I was working on a site that needed an iframe embedded in the page whose content came from a completely different domain. I try to steer clear of iframes at all costs normally so forgive me if what I’m about to say is pretty obvious.

I didn’t want the content in the iframe to appear as though it was in an iframe, so obviously I stripped off all the default browser styles…well, the border. I wanted the iframe to be as high as the content it was containing so that no scroll bars would appear.

So what I did was just give the iframe a height, however when the user navigated to a different page within the iframe, the height I had previously set was too big or too small.

I instantly thought “right, JavaScript will sort this out for me!” and proceeded to quickly code up a function that would inspect the scrollHeight of the content in the iframe and adjust the iframe height accordingly.

No! Said cross domain policy. I had momentarily forgotten all about that. Since the iframe content came from a different domain, I wasn’t allowed to access the document object of the iframe (or vice versa).

Here is how not to do it

Firefox says “Error: Permission denied to access property ‘document’” and other browsers similar.

I started searching for some kind of workaround.  Of course there isn’t really one…except I did find an interesting hack for Firefox. Which is – an iframe document can alter the url fragment of the parent window’s location object! ha madness.

The idea is that the document in the iframe alters the url fragment to read:

http://freestyle-developments.co.uk/blog/?p=150#138

Where 138 is the height of the iframe document (obviously you could be a bit more fancy and send other parameters and name them e.g #height:138 but for simplicity I’ve just set the value). The parent then reads this value and sets the iframe height accordingly:

var iFrameHeight = parseInt(location.hash.replace('#', ''));

So…yeah, that’s pretty interesting, but not really a solution. Check out the example implementation here.

Anyway, what to do? HTML5 web messaging to the rescue! Sweet! HTML5 web messaging is cross domain messaging done right. Not only does the messenger choose who should receive messages, but the recipient also chooses who to receive messages from.

The idea is that after the iframe document has loaded, it sends a message to the parent window telling it what it’s scrollHeight is. The parent listens for messages, and sets the height of the iframe when it receives a message.

A couple of things to note:

  1. There has to be communication between the two documents. i.e. the document on the external domain needs to actively send this message. Which can be a complete show stopper if you have no control over the document on the external domain
  2. This isn’t going to work on IE < 9. I tested the implementation linked below is working on FireFox 4 (Beta 7), Safari 5.0.2, Chrome 8, Opera 10.63 and Internet Explorer 9 Platform Preview 7. Which is a pretty good spread to be honest

Check out the example HTML5 web messaging implementation here.

VB.NET and project imports

Much to my displeasure, I’ve recently inherited an ASP.NET 1.1 website. After a bit of a wrestle they eventually handed over the source code (Why are .NET developers so precious over their code?). Unfortunately they didn’t hand over the Visual Studio project or solution files as well.

Fair enough, I can easily create a new solution and import all the code…no problem. Except there were problems, 104 of them. If you’ve used Visual Studio before you’re likely to know what that means. It means: a shit load of errors, except I’m only going to show you 104 of them.

The kind of stuff I was getting was:

Type 'Control' is not defined.

…and there were no error messages for missing imports. I scratched my head for ages until I thought of the notion of “automatic imports”. What if, these guys have somehow specified a set of imports that get appended automatically to each file…which I haven’t defined?

Turns out, you friggin can do exactly that. In Visual Studio 2003 it is: Right click on project > properties > project properties > imports.

Who the hell thought of that? Surely it is a completely ludicrous idea! It means that if the code gets separated from the project (which is exactly what happened) it won’t work correctly. Not only that, but how the hell am I supposed to know if MyClassName belongs to com.companyX.package or com.companyY.package???

So I’m just totally guessing at the moment, and I’m down to 18 errors. Man I hope it eventually runs.