Onward and Upward with jQuery: Reworking My External Links JavaScript

I’ve been watching so many folks out there doing cool things with jQuery, and it’s time to bite the bullet and get up to speed.  I wanted to take a look at something I’d recently posted about and see how I could do it with jQuery rather than pure JavaScript to see what the differences might be.  Sort of my own personal “Hello World”.  A good candidate seemed to be my post entitled  External Link Indicator for SharePoint Pages Using JavaScript.  The basic idea is to show a little external link icon whenever a link is going to take to to a different hostname, like this:

image

There’s no real reason to write this from scratch, as there are some good examples out there, such as the one from Karl Swedberg (Quick Tip: Dynamically add an icon for external links) and others.  However, I wanted to try to mirror my earlier implementation exactly, which was a little different in that I used a CSS class to contain the icon reference and the spacing so that I could easily adjust over time, as needed.

So, first of all, I went and grabbed the jQuery code and put the .js file in a Document Library in my test site.  Then I added a reference into my test page:

<asp:Content ContentPlaceHolderId="PlaceHolderAdditionalPageHead" runat="server">   
<META Name="CollaborationServer" Content="SharePoint Team Web Site">    
<script type="text/javascript" src="Document Library/jquery-1.3.2.js"></script>    
</asp:Content>

Next I grabbed Karl’s jQuery code and added it after the jQuery reference in my page.  I made adjustments, as follows:

  • Added a new CSS class (ExternalLink) rather than appending the icon directly in the DOM
  • Made sure that the links that are marked are only within the main content table with id=MSO_ContentTable
<asp:Content ContentPlaceHolderId="PlaceHolderAdditionalPageHead" runat="server">   
<META Name="CollaborationServer" Content="SharePoint Team Web Site">    
<script type="text/javascript" src="Document Library/jquery-1.3.2.js"></script>    
<script type="text/javascript">    
$(function() {    
    $('#MSO_ContentTable a').filter(function() {    
        return this.hostname && this.hostname !== location.hostname;    
    }).addClass('ExternalLink');    
</script>    
</asp:Content>

So the jQuery code is definitely smaller and tighter.  I also found it easy to tweak, once I’d skimmed through some of the tutorials.  I think I’ll try reworking a few more of my JavaScript examples when I get a little time.

External Link Indicator for SharePoint Pages Using JavaScript

Many so-called Web 2.0 sites show a little icon for any links which send you out of their purview to another site.  This is a nice thing to do within SharePoint as well.  You can easily make this happen without users needing to take any action by adding some JavaScript into your master page.

I got the basics for this from a post entitled Useful Links with JavaScript by Toby Somerville over at SitePoint.  Also check out his http://ikonize.com/ site for examples.  Thanks to Toby for the approach and the parseURL and the qualifyHREF functions.

What the JavaScript below does is look for all of the links within the main content pane of SharePoint pages (the table with the id=”MSO_ContentTable”) and add the ExternalLink CSS class to them if they lead outside the current server context.  I wanted to limit things to the main content pane for several reasons. First, there may be links in other parts of the page that we just don’t want to make look different (e.g., the footer), and secondly, in MOSS the My Site link at the top of the page takes you to a different Web App, and I didn’t want to show the external link icon there.  Obviously, you can adapt the JavaScript based on what you’d like to do.  I built this for use with a master page in MOSS that is based on default.master with minimal customization.

First, put the JavaScript below into a file somewhere in your Site Collection (I always create a Document Library called JavaScript in the root site of the Site Collection) and then add a script line into the <HEAD> section of your master page:

<script language="javascript" type="text/javascript" src="/JavaScript/ExternalLinks.js"></script>

Then call the StyleExternalLinks() function in the onload event of the <BODY>:

<BODY scroll="yes" onload="javascript:if (typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();StyleExternalLinks();">

In my custom CSS, I’ve added a new class called ExternalLink, defined as follows:

a.ExternalLink {
  background-image:url('/SiteCollectionImages/ExternalLink.jpg');
  background-repeat:no-repeat;
  background-position:right top;
  padding-right:15px;
}

You could pretty easily expand the JavaScript below to highlight other link types as well, but my focus was on external links:

// Sets a class to all external links
function StyleExternalLinks() {
    thisHost = parseURL(qualifyHREF(document.location.href)).hostname;
    tables = document.getElementsByTagName(“TABLE”);

    for (i = 0; i < tables.length; i++) {         // Only apply external link icon for links in the main pane         if (tables[i].id == "MSO_ContentTable") {          anchors = tables[i].getElementsByTagName("A");             for (a = 0; a < anchors.length; a++) {                 thisLinkHost = parseURL(qualifyHREF(anchors[a].href)).hostname;                 if (thisLinkHost != thisHost) {                     anchors[a].className += "ExternalLink";                 }             }             // Since this is the main pane, we're done             return;         }     } }     //parse a URL to form an object of properties     function parseURL(url){         var loc = {             'href': url         };         var parts = url.replace('//', '/').split('/');         loc.protocol = parts[0];         loc.host = parts[1];         parts[1] = parts[1].split(':');         loc.hostname = parts[1][0];         loc.port = parts[1].length > 1 ? parts[1][1] : ”;
        parts.splice(0, 2);
        loc.pathname = ‘/’ + parts.join(‘/’);
        loc.pathname = loc.pathname.split(‘#’);
        loc.hash = loc.pathname.length > 1 ? ‘#’ + loc.pathname[1] : ”;
        loc.pathname = loc.pathname[0];
        loc.pathname = loc.pathname.split(‘?’);
        loc.search = loc.pathname.length > 1 ? ‘?’ + loc.pathname[1] : ”;
        loc.pathname = loc.pathname[0];
        var dotty = loc.pathname.split(‘.’);
        if (dotty.length > 1) {
            loc.extension = dotty[(dotty.length – 1)];
        }
        else {
            loc.extension = ”;
        }
        return loc;
    }
    //qualify an HREF to form a complete URI
    function qualifyHREF(href, context){
        var here = document.location.href;
        var bases = document.getElementsByTagName(‘base’);
        if (bases.length > 0) {
            var basehref = bases[0].getAttribute(‘href’);
            if (basehref && basehref != ”) {
                here = basehref;
            }
        }
        if (typeof context == ‘string’ && context != ”) {
            here = context;
        }
        var parts = here.replace(‘//’, ‘/’).split(‘/’);
        var loc = {
            ‘protocol’: parts[0],
            ‘host’: parts[1]
        }
        parts.splice(0, 2);
        loc.pathname = ‘/’ + parts.join(‘/’);
        var uri = loc.protocol + ‘//’ + loc.host;
        if (/^(\.\/)([^\/]?)/.test(href)) {
            href = href.replace(/^(\.\/)([^\/]?)/, ‘$2’);
        }
        if (/^([a-z]+)\:\/\//.test(href)) {
            uri = href;
        }
        else
            if (href.substr(0, 1) == ‘/’) {
                uri += href;
            }
            else
                if (/^((\.\.\/)+)([^\/].*$)/.test(href)) {
                    var lastpath = href.match(/^((\.\.\/)+)([^\/].*$)/);
                    lastpath = lastpath[lastpath.length – 1];
                    var references = href.split(‘../’).length – 1;
                    var parts = loc.pathname.split(‘/’);
                    parts = parts.splice(0, parts.length – 1);
                    for (var i = 0; i < references; i++) {                         parts = parts.splice(0, parts.length - 1);                     }                     var path = '';                     for (i = 0; i < parts.length; i++) {                         if (parts[i] != '') {                             path += '/' + parts[i];                         }                     }                     path += '/';                     path += lastpath;                     uri += path;                 }                 else {                     path = '';                     parts = loc.pathname.split('/');                     parts = parts.splice(0, parts.length - 1);                     for (var i = 0; i < parts.length; i++) {                         if (parts[i] != '') {                             path += '/' + parts[i];                         }                     }                     path += '/';                     uri += path + href;                 }         return uri;     }[/sourcecode]