Helpful Hyperlinks with JavaScript

    Toby Somerville
    Share

    There you are happily surfing a web site; you click a link and suddenly find yourself at another site being asked to download a file. What happened there? Annoying, isn’t it? There has to be a better way to indicate to your visitors where a link is going and to what type of file. So, to help solve this little annoyance, I’ve written a bit of JavaScript and CSS that adds pretty little icons after the links – depending on the file extension and location – to indicate to the user the type of document they’re about to load.

    Iconized links

    You can download the code here, and see an example.

    The Brief

    The main considerations when creating this functionality were:

    1. simplicity – it must be easy to use
    2. graceful degradation – in the case of CSS or/and JavaScript being disabled
    3. minimal use of files – only one JavaScript and one CSS file
    4. making it as plug-and-play as possible – so it can be quickly added to a site
    5. limiting the overall amount of code
    6. compatibility with all modern browsers, including IE6

    Why the shift away from a CSS-only solution?

    You can already do this in CSS, using attribute selectors. Here’s an example:

    a[href$='.doc'] { 
     display: inline-block;
     padding-left: 16px;
     background: transparent url(images/icon_doc.gif) center right no-repeat;
    }

    So why would you do it with a script, when most modern browsers will display the icons using just CSS?

    The answer is simple: IE6. All decent browsers support CSS3 attribute selectors … except IE6. This bit of scripting with CSS makes IE6 play nicely; in fact, it even works in IE5.5.

    Inspiration and Credit

    Before we get started, I’d like to acknowledge the excellent – and free – Silk icons by Mark James at famfamfam, which we’ll be using in this article.

    Silk icons

    Also, credit where credit is due: this article was inspired by the piece Iconize Textlinks with CSS by Alexander Kaiser, which was in turn inspired by Ask the CSS Guy’s Showing Hyperlink Cues with CSS. In addition, I’ve used a couple of excellent functions written by SitePoint’s very own James Edwards, and a couple more taken from the Core JavaScript Library, written by Kevin Yank and Cameron Adams and immortalized in the SitePoint book, Simply JavaScript.

    So how does it work?

    Well, in a nutshell: we take all the links in the page, work out the file extension it links to, and then we add the appropriate icon after the link. Nice.

    To make it all work, there are three files involved:

    1. the HTML page containing the links, index.html
    2. the CSS file containing the icon classes, iKonize.css
    3. the JavaScript file that adds the CSS classes and icons to the links, iKonize.js
    The Quick-Start Method

    Now, if you’d like to sidestep the whys and wherefores, and just want to add it to your page, here’s the short version:

    1. Add the links to the JavaScript and CSS files in the header of the page (change the file references to suit your site setup).
      <link type="text/css" rel="stylesheet" href="iKonize.css"/>
      <script type="text/javascript" src="iKonize.js"></script>
    2. Put your icons folder up on your site and make sure the url references are correct in the iKonize.css file.
    3. Call the JavaScript function iKonize from a script tag included just before the closing body tag, like so:
      <script type="text/javascript">iKonize();</script>

    See – I told you it was simple to use!

    For simplicity’s sake, I’ve opted to call the function from within the HTML after the DOM has loaded. There are other ways to achieve this using JavaScript, but they’re beyond the scope of this article.

    The Full Explanation

    Make yourself comfortable, we’re going to delve into the inner workings.

    Configuration

    In the spirit of keeping things simple, most of the setup is already done for you. You’ll only have to change the configuration if you need to alter the icons or file extensions. There are two places to make these changes: the JavaScript (iKonize.js), and the CSS file (iKonize.css).

    Configure iKonize.js

    At the top of the file you’ll see all the configuration variables: classPrefix, classExternal, and classIconLoc.

    classPrefix is the prefix you want to give the individual CSS classes. Use this to prevent any conflicts with any existing CSS classes. The default is iKon_.
    classExternal is the name of the CSS class you want to use to show a link to an external site.
    externalIconLoc is the location of the image to use for the external icon.

    Which links will receive an icon?

    To define what type of file the link goes to, we’ll look at the file extension. The file types are split out into two groups: those that have unique icons, such as torrent files, and those that will share the same icon, but have different file extensions, such as Flash files (.fla and .swf).

    Grouping file extensions that share the same icon saves you having hundreds of CSS classes and icons. To achieve this I have created two arrays.

    The first array, IndividualClassArray, holds the file extensions of all the links with individual icons. The base of the CSS class name is the same as the file extension. That is, a text file is referenced with ‘txt‘ and the CSS class name is the classPrefix (set earlier) and ‘txt’ the base CSS class name, making a CSS class called ‘iKon_txt’ in this case.

    IndividualClassArray = Array('txt', 'xls', 'css', 'torrent');

    The second array, classArray, is actually a multidimensional array, but don’t let that put you off. Basically, it’s a group of individual arrays grouped according to the kind of icon we’d like to use. The first item in this array is IndividualClassArray (this array must always be the first array). The following arrays are similar to the previous array with one important difference: the first item in each of the arrays is the name of the CSS class that will be used, and the following items are the file extensions which need that class. In the following example the .swf and .fla file extensions will be associated with the ‘flash’ CSS class.

    classArray = Array(  
    IndividualClassArray,  
    Array('flash', 'swf', 'fla')  
    );

    Note: File extensions exclude the dot, that is, xls not .xls.

    For maximum portability, the actual CSS class name used will have a prefix such as ‘iKon_’, which we configured earlier – but in these arrays we always exclude the prefix. So a Flash CSS class is always referred to as ‘flash’ rather than ‘iKon_flash’.

    External Links

    To figure out whether a link is an external site, we need to know the host name of the current page.

    For this we use:

    url = parseURL(qualifyHREF(document.location.href)).hostname;

    This takes the current document’s location and gets the domain name using the qualifyHREF function to make sure we have a fully qualified address and the parseURL function to get the host name. (Both of these functions were written by our resident JavaScript guru, Brothercake, and covered in his blog post). Later, when we add the classes for the external links, we’ll use this host name to work out whether the link is external to our site.

    The Code That Actually Does the Work

    Now we need to get all the links from the page using document.getElementsByTagName("a"), and determine the file extension of the link.

    We do this by using the functions parseURL and qualifyHREF again.

    First, take the href value of the a element:
    linkHref = aElements[iv].href;

    Next, parse the value to gain more information about the link:
    oUrl = parseURL(qualifyHREF(linkHref));

    Then get the extension for the link:
    fileExt = oUrl.extension;

    Then, we need to loop through these links and work out whether they need an icon. This is where it starts to become a little bit trickier. We need to loop through classArray and each of the arrays it contains. We do this by running a loop within a loop. Yes, that’s a loop, in a loop, in a loop! This hairy piece of code looks like this:

    aElements = document.getElementsByTagName("a");  
    iElements = aElements.length;  
     
    for (iv = 0; iv < iElements; iv++) {  
     iLen = classArray.length;  
     for (ii = 0; ii < iLen; ii++) {  
         iArr = classArray[ii].length;  
           for (i = 0; i < iArr; i++) {  
               // Do we need to add an icon?  
             }  
        }  
    }

    Does this link require an icon?

    To find out if we need to add an icon, we’ll compare the file extension of the link with each of the extensions listed in our arrays.

    if (fileExt == classArray[ii][i]) {      
       if (ii === 0) {  
          linkClass = fileExt;  
       }  
       else {  
          linkClass = classArray[ii][0];  
       }  
       bFound = true;  

    Now we know if the link needs an icon, and which class it needs. We'll add that class using the addClass function we've grabbed from the Core JavaScript Library.
    if (bFound && linkClass !== '') {  
       addClass(aElements[iv], classPrefix + linkClass);  
    }  

    Links to External Sites

    Working out if the link is to an external site is just a case of comparing the URL host name we determined earlier with the URL we set in the configuration area.

    if (oUrl.hostname.indexOf(url) == -1) { // not our url  
       bExternal = true;  
    }

    If it’s true, we’ll append a new image element in the anchor, add a source and ID, and then add an alt and title attribute for the image. We add the extra icon rather than just assigning a class to clearly show that this link goes to another site, as well as adding title and alt attributes to the icon.

    if (bExternal) { //  an external link  
      img = document.createElement('img');  
      img.id = 'Newimg' + iv;  
      img.src = externalIconLoc;  
      img.alt = 'external site';  
      img.title = 'links to an external web site';  
      void (aElements[iv].appendChild(img));  
      oimg = document.getElementById("Newimg" + iv);  
      addClass(oimg, classExternal);  
    }

    The CSS Classes

    Let’s move back to the CSS file now.

    Here is our CSS class to add the icon to .doc files. Notice the class name is prefixed with ‘iKon_‘ and then the file extension ‘doc‘. This class basically puts a bit of padding in the top and bottom, and to the right of the link. It then adds a background image of the icon into that space.

    .iKon_doc {  
     padding: 5px 20px 5px 0;  
     background: transparent url(icons/icon_doc.gif) no-repeat center right;  
    }

    For our external link icons, we’ll use a slightly different class structure. We add some padding top and bottom to make sure our icon is borderless.

    .iKon_external{   
     padding: 5px 0 0 5px;  
     border: 0;  
    }

    If you changed the classPrefix variable, don’t forget to alter these class names to match.

    Limitations

    The link must have a file extension to have an icon assigned to the link (unless it’s an external site). The script also doesn’t recognize query string- based navigation links. If CSS is disabled, then only the external link icon will display and if JavaScript is disabled, then there are no visible changes to the page.

    Conclusion

    iKonize is a quick and easy way to add visually meaningful icons after links. The script works in IE5.5+ and can work independent of CSS3 attribute selectors. As you might expect, the script degrades well and is easily configured. I hope you find it useful!