Clint Patterson's Blog


Read the thoughts and musings of a cultured redneck here

JQuery Leaving Site Alert with External Link Icon for MOSS 2007
Specify Alternate Text
My wife and I recently celebrated our 1 year anniversary. We went on a weeklong trip to Turks & Caicos and like any loving husband would do, I bought two books to read during our vacation!  I bought a CSS3 book and a JQuery book. Yes I?m behind in all the trends, but I?m slowly making my way.  I knew a little about CSS3 and very little about JQuery so I figured I try to get clued in some so I wouldn?t be too far behind times. 
I really enjoyed both books and I?m still working on finishing the JQuery book.  As anyone would probably do, I started playing around with some code snippets seeing what I could make happen.  I used some of the CSS3 concepts I learned here in the design of this site and started using some small JQuery snippets at work.  I began showing some of my co-workers things I was testing out and before I knew it I was getting all kinds of questions about JQuery that I had no business fielding.  I?m sure similar scenarios may have happened to you before when you start learning something new, then you mess up and show someone an example, and all of a sudden you get coined the ?Champion? of whatever it is you?re investigating and a flood of requests ensue.  Fun times.
The Task
It didn?t take too long before I was tasked with trying to figure something out for our site.  The initial task was to use JQuery to add a small icon beside any link that was an external link to our site.  This had to be done in a way to where our end users wouldn?t have to take an additional step, but rather JQuery would find these external links and insert the icon dynamically.  This would give our site visitors a better user experience, cover us in case of some rare legal matter where someone thought they were on our site and something bad occurred, and wouldn?t require any extra steps on the part of our content managers.
First Steps
The JQuery book I have has many examples, but I was looking for a specific one so I started Googling and found some very helpful JQuery snippets on various sites.  The JQuery code I ended up using was a version from that I modified a little bit. The script from Learning JQuery?s site is posted below.  

$(document).ready(function() {
    $('#extlinks a').filter(function() {
          return this.hostname && this.hostname !== location.hostname;
     }).after(' < img src [equals] "/images/external.png" alt="external link"/ >');

The main part of the code that I needed was the 

            ?return this.hostname && this.hostname !== location.hostname? 

This snippet compares the path of a link to the host site?s address and if they differ then JQuery adds an image (specified by the img src path) after the link.  This code does work, but if you notice the code is selecting links that reside in a class by the name of ?extlinks?.  In my scenario I needed the JQuery code to select the links without the users having to take an additional step and there?s no way that our end-users (literally hundreds across the organization) would be able to apply a class to a link that was external (and be happy about it).  This code got me closer, but didn?t ultimately do what I needed it to do.
I thought about it, Googled, and researched more and then tried a different method.  I still wanted to use the URL path comparison part of the script, but instead of adding an image after the link I figured I should add a class to the link.  Doing it this way would allow me to find the links and add the small icon without the content manager having to take an extra step.  So I created a class called ?externallink? with this code.
    background: url( center right no-repeat;
This style uses the external icon as a background image that sits just to the right of any external hyperlink.  This doesn?t allow for any alt text on hover, but I?ll take that rather than asking all of our content managers to apply styles to external links.  The updated JQuery script to add the additional class looked like this:
The Updated Task
Success?at least momentary? I thought.  I sent out an email with a link to an updated page to my co-workers and they started giving feedback on it.  Of the feedback the two crucial ones were ?That looks good, but can you make it pop-up a message to the users that lets them know they?re leaving our site? and ?What about some of the applications maintained inside our site, but that have different URLs.?  So my second JQuery script attempt was shot down within minutes.  Additionally, I started thinking about it and I went to test out what would happen if an image got hyperlinked and, as you would imagine, the icon was added just to the right of the image. In some cases this distorted page margins when images were using the max-width of content areas.  
There?s also one more thing to add.  The site I was implementing this script on has a ?Dev? server an ?Authoring? server (where edits are made) and a ?Production? server where the live site resides.  One other thing that I noticed was that the current script was looking at the authoring server?s URL, and since it was different, ever link pretty much had an external icon. Though, once the page was published and on the production server everything looked the way I anticipated.  This would probably raise questions to our content managers if they saw a ton of external-link icons in their editing environment. This was yet another reason to filter out specific URL paths.
It was evident that there needed to be 3 additional updates to the script:
  • It had to be able to cull out specific URLs that were still ?internal? to our site and organization even though they had different URLs
  • It had to disregard images, anchor tags, & mailto tags
  • And it needed pop-up a message letting users know they were exiting the site
The Road to the "Solution"
With the updated requests I had to go back to the starting blocks.  I always love it when that happens!  Since part of the updated request was to be able to cull out specific URLs I had to find a way to make this happen.  I ended up using some of the JQuery Selectors to filter out the href values in the URLs. If the path contained certain words that are specific to our URL then I remove the externalink class that was added & add a new internallink class to it. The newly created internallink class has an empty background image. I thought it should work without adding the internallink class to it, but for some reason it didn?t, so I?m going with what works at this point.
The additional CSS class
.internallink { background: url(); }
The JQuery
//If the URL is a "mailto:" tag (to send an email) then add the class "internal" to the link
//If the URL is an anchor(contains "#" in the path) then add the class "internal" to the link $("a[href*='#']").removeClass('externallink').addClass('internallink');
//If the URL contains "" in the path then add the class "internal" to the link $("a[href^='']").removeClass('externallink').addClass('internallink');
That code allowed me to filter out specific URLs, #?s, and mailto links.  I still had the problem of hyperlinked images having external icons added to them as well as I still needed to get the pop-up message alerting users that they were leaving our site.
The ?Leaving Site Alert?
It wasn?t too bad as far as figuring out what code to insert to give the user a pop-up message alerting them that they were leaving our site.  I used the typical javascript style pop-up message by adding the code below:
//When an external link is clicked pop-up the exiting site message
      alert('You are leaving');
This just finds any link that has been cast as an external link and adds the pop-up message when it is clicked.
Removing the Icon from Images
I struggled with trying to figure out the code to remove the externallink icons from images that were hyperlinked.  I tried and tried (and in retrospect I was close), but couldn?t figure it out.  I posted a Tweet to my twitter account and shortly thereafter Johnathan Sheely responded with the exact line of JQuery code that did the job (Insert big thanks to Johnathan here!).  The code snippet he tweeted to me was:
$("div a img").each(function(){$(this).parent().removeClass("externallink")
This code removed the class of externallink from any hyperlinked image and met the goal.  After implementing this I realized that the images still needed to have the pop-up message shown even though they didn?t need the little icon.  This was easily achieved by creating a new class (with no properties) of externalimage and adding it into the script.  This would allow me to cast hyperlinked images as externallinks, but yet remove the icon from them.  The updated script?
$("div a img").each(function(){$(this).parent().removeClass("externallink").addClass("externalimage");});
Then I just added a click function to the externalimage class and the images now had no icon + a pop-up.
      alert('You are leaving');
The Solution (as of today)
I didn?t think buying a JQuery book would get me into this much trouble.  I am by no means a JQuery guru and I think there is probably a better solution for this problem out there.  If you have any insights into this scenario feel free to post in the comment section below.  
Found 2 exceptions and needed to update the post. Inside the CMS many of the link clicks run "javascript void()" scripts.  So when someone, in edit mode, clicks the "preview" button button they would get the message "You are leaving Mecklenburg County".  To overcome this I added a line to make any a href with the text "javascript" in it be cast as an internal link by adding this line:
The other issue was similar, but I had to go about fixing it in a different manner.  When clicking the Site Actions button the JQuery script would fire the "You are leaving Mecklenburg County" message.  Took me  a bit to figure out what was happening, but the Site Actions button is using an image as the link and the script was casting it as an "externalimage"...just the way I coded it to! The way I overcame this was to filter the path of the hyperlinked image.  This image resided in a folder that had the path of " _layouts " in it.  I updated the script to remove the class of "externalimage" add the class of " internallink " to any hyperlinked image with the path of "_layouts " in it as shown below:
//If the path for the img source has "_layout" in it then add class "internalink" to the link
$("div a img[src*='_layouts']").each(function()$(this).parent().removeClass("externalimage").addClass("internallink");});
This did the trick and now I think the script is usable inside of MOSS 2007.

Clint Patterson

I also blog on other sites...

And contribute to OSS Documentation...

See my pics on UnSplash