April 2008
Posted on the 4th at 6:03 PM CST
Opening External Links in a New Window Based on User Preference
FiledFiled under Javascript

I spend alot of time surfing the Internet. Who doesn't? When I come across an outgoing link (when I say outgoing, I mean a link to a page that resides on a different domain), I always have to make a decision. As an end user, I am clueless as to whether or not the link will open up in a new window. Perhaps the browser is to blame for this. Regardless, I don't usually take any chances, so I right-click the link and choose to open it in a new window/tab. Every potentially suspicious link (most of them are) requires at least two clicks. I have reached the point that I do this instictively, without even thinking about it. I honestly feel the browser should be responsible for telling the user which links will be opened externally, and perhaps there should also be settings in place for the user to specify how they want all links to behave, depending on anchor tag attributes such as target="_blank" and rel="external". It doesn't take long before you realize that waiting for browsers to do what you want is a lost cause, no matter what religion you are or how often you pray. So, I took action. I came up with a Javascript solution that puts the choice in the user's hands.

In my opinion, an ideal solution would be to setup a link/button/checkbox/whatever on your site that, when the user clicks it, will execute some Javascript to force all external links to be opened in a new window. On top of that, the users preference should be "remembered" by storing it in a cookie. You might have seen something like this before. I think this is a pretty damn user-friendly approach. In light of that, I have prepared an elegant script that performs the duty, and is quite simple to implement and extend. Before getting to the juicy code, allow me to explain how it works.

Nuts and Bolts, Baby!

When the web page loads, my script will look for the existence of a cookie. The cookie it's looking for will be one that the same set of Javascript previously created. If it finds it, it will loop through the links accordingly and attach an onclick event handler to open the HREF in a new window (or tab, depending on how your browser settings are configured). If it does not find the cookie, it does nothing. So users without the cookie will have the default link behavior; the target attribute of the links will still be effective. You, the developer of the web site, are responsible for coming up with a stylish link/button/checkbox for the user to make their selection. All you have to do is call a Javascript function when the user clicks this element, with one boolean parameter, and that's it. The rest is done for you. Passing true to the function will make all outgoing links open in a new window. Passing false will make them all open in the same window. This function sets the cookie and loops through every <a> tag on the page. If the HREF attribute points to an external web site, it will be opened in a new window when clicked (if the boolean parameter was true). It's a relatively simple concept, right? Turning concept into code is not as simple. Luckily for you, I've got it all taken care of.

I created an unobtrusive object model that is straight-forward and is nice and simple to use. Most importantly, you can add the feature to an existing site pretty easily. I have tested the code in all major popular browsers as of today (April 2, 2008), and it worked great in all of them. If you have any questions on how to modify this script to your liking, don't hesitate to ask. Here is the Javascript code…

function addLoadEvent(func) {
  if(typeof window.onload != 'function')
    window.onload = func;
  else {
    if(func) {
      var oldLoad = window.onload;

      window.onload = function() {
        if(oldLoad) oldLoad();
        func();
      }
    }
  }
}

var Links = {
  IsCapable: (document.getElementsByTagName),
  CookieId: 'MyLinkCookie',
  GetCookie: function() {
    var vals = document.cookie.split(';');

    for(var i = 0; i < vals.length; i++) {
      var val = vals[i].replace(/^\s+/, '');

      if(val.indexOf(Links.CookieId) == 0)
        return val.substring(Links.CookieId.length + 1, val.length);
    }

    return null;
  },
  SetCookie: function(bool) {
    var dat = new Date();
    dat.setTime(dat.getTime() + 63072000000); //2 years

    var val = Links.CookieId + '=' + bool;
    var exp = '; expires=' + dat.toGMTString();
    var path = '; path=/';

    document.cookie = val + exp + path;
  },
  RemoveCookie: function() {
    document.cookie = Links.CookieId + '=false; expires=Fri, 02-Jan-1970 00:00:00 GMT; path=/';
  },
  SetExternals: function(bool) {
    Links.SetCookie(bool);
    Links.Scan();
  },
  Scan: function() {
    var bool = Links.GetCookie();

    if(!Links.IsCapable || !bool)
      return;

    var links = document.getElementsByTagName('a');

    for(var i = 0; i < links.length; i++) {
      var href = links[i].getAttribute('href');

      if(href.substring(0, 5) == 'http:' || href.substring(0, 6) == 'https:') {
        var pageUrl = location.protocol + '//' + location.host;

        if(href.substring(0, pageUrl.length) != pageUrl) {
          if(bool == 'true') {
            links[i].onclick = function() {
              var winId = 'win' + Math.random().toString().substring(2);
              var newWin = window.open(this.href, winId);
              newWin.focus();
              return false;
            }
          }
          else
            links[i].onclick = null;

          links[i].removeAttribute('target');
        }
      }
    }    
  }
}

addLoadEvent(Links.Scan);

Uhhhh, How Do I Use This Code?

I won't leave you hangin' with just a chunk of Javascript; I have setup a demo page illustrating the functionality. It is simple, really. All you have to do is bring in the script into your page (with <script> tags, respectively). There are two main functions: Links.SetExternals and Links.RemoveCookie. SetExternals is the function I mentioned earlier that expects the boolean parameter. Calling the RemoveCookie function will essentially return link behavior to the default.

The demo uses standard hyperlinks to set the preference, but I think a checkbox is probably the most practical thing to use here, which can be done rather easily just like this...

<input type="checkbox" onclick="Links.SetExternals(this.checked);" />

So go ahead, make your visitors happy by giving them a useful option. If you have any problems using this script, or any relevant questions, feel free to express yourself. That's all folks, enjoy!

Comments (7)
Permalink Comment from Adam Kahtava on April 4th, 2008 at 7:56 PM
That is pretty nifty, but what about the middle button (mouse wheel) click? I always use that button to open a new tab. Or what about the mouse gesture (https://addons.mozilla.org/en-US/firefox/addon/39) click, drag up to open a new tab?
Permalink Comment from Josh StodolaEmail on April 4th, 2008 at 11:06 PM
Yeah, the mousewheel click thing is definitely easier than right-clicking, but I still have yet to get out of the habit. What about links with target="_blank" that you want to open in the same window?
Permalink Comment from Adam Kahtava on April 4th, 2008 at 11:27 PM
True-true... You should roll this up into a Greasemonkey userscript ( http://userscripts.org/ )!
Permalink Comment from Will on April 5th, 2008 at 2:47 PM
I add this to my outgoing links so people will know when they hover over the link what will happen: title="(opens in new tab)"

-Will
Permalink Comment from Josh StodolaEmail on April 5th, 2008 at 3:21 PM
That is a nice thing to do. It's tedious "busy work", though.
Permalink Comment from Muhammad Mosa on April 6th, 2008 at 2:25 PM
Beautiful and cool idea. You made me think of a repost using JQuery!!
Permalink Comment from Blogging Developer on July 3rd, 2008 at 6:11 AM
Great. Thank you.

Guess What?

There are a few basic guidelines you should be aware of before leaving a comment…

  • If you choose to display your email address, it will not be detected by spam bots
  • Comments are limited to 3,000 characters; so far you have used none of them
  • HTML will be encoded; links and line breaks will be converted automatically
  • Comments containing five or more links will be subject to moderation

Have Your Say

← Answer this to prove you are human
 
 

Chill Out…

No Trackbacks