Identify external links in JavaScript

Apr 1, 2007

Many websites have started to add a little icon next to external links, so that visitors know that if they follow it, they will leave the website. Here is a small JavaScript that adds a class called external to all off-site links on the page. Just call the function when the page has loaded.

// Sets a class to all external links
function StyleExternalLinks()
{
 var divs = document.getElementsByTagName("div");
 for (i = 0; i < divs.length; i++)
 {
  var anchors = divs[i].getElementsByTagName("a");

  for (a = 0; a < anchors.length; a++)
  {
   if (anchors[a].href.substring(0,13) != location.href.substring(0,13))
    anchors[a].className += "external";
  }
 }
}

The function searches all DIV tags for links. Now you just need to style the class in order to display the icon.

a.external {
  background: url(../../pics/remote.gif) right top no-repeat;
  padding-right: 9px;
}

Here is an icon you can use  (right-click and Save picture as...).

* $4.95/month BlogEngine.net Hosting – Click Here!

Comments (4) -

Damir
Damir Sweden
5/1/2007 8:12:25 PM #

It's a nice solution, but why use anything else than css? I've noticed that link icons in BlogEngine "jump in" after the page is loaded, and that's not so pretty.

For all modern browsers you can use this in your styles instead:

First you create an icon for all links that begin with http:
------------------------------------------------------------
a[href^="http:"] {
  background: url(external.gif) no-repeat right top;
  padding-right: 10px;
}
----------------------------------------------------------------------
Then you exclude your own url (and localhost, for your development machine...
----------------------------------------------------------------------
a[href^="http://localhost/devurl"],a[href^="http://www.yourdomain.com";]{
  background-image: none;
  padding-right: 0;
}
----------------------------------------------------------------------
There you go... no javascript, just plain old css.

You can use this stuff to put email icon on mailto: links, and with modification you can mark all your files with right icon, for example pdf, word, etc...
Just check if the link ends with .pdf, .doc etc (a[href$=".pdf"])

Have fun,

Damir
Damir Sweden
5/1/2007 8:15:38 PM #

Bah...
Code looked good in the preview, but all my linebraks were eaten up in the comment.
Sorry for that, dunno if I could put in class="code" around it...

Mads Kristensen
Mads Kristensen Denmark
5/1/2007 9:23:26 PM #

I got it perfectly formatted in the e-mail i receive on each comment. Thanks for the code.

JoeGeeky
JoeGeeky United States
5/30/2007 7:32:13 PM #

I am a little late on this post but here it goes...  Looking at your older HttpModules, I asked myself why this could not be done using a module and potentially introduce a wider range of features such as:

- Appending notations to the links tooltip (Ex. (Remote Site))
- Redirection through exit notification pages (Ex. redirect to a specific URL and show them a message such as "You are now leaving my site... Cya"). Here I would encode the original URL and make it a query string to the redirect URL
- Setting the link target (Ex. "_blank").
- Append the remote link className to the existing class name and not just replace any existing one.
- Management of options using a custom module ConfigurationSection which could be set per app or set in the runtime Web.Config and be applied to all hosted apps.
- Identify more then one URL as a safe/internal URL
- This could be extended to also make changes to ASP.NET Hyperlink Controls
- Wire up new events on the fly
- Etc, Etc, Etc...

I recently added this to my server and all hosted apps received the change.  The only problem was that the image did not show up until the CSS Class was made accessible to the various apps.  Other then that, all other aspects worked...

Using YOUR HTTPModule pattern as an example, here is a sample of how it works. This is the write event of the modules internal Steam class.

   Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)

      Dim data(count) As Byte
      System.Buffer.BlockCopy(buffer, offset, data, 0, count)

      Dim html As String = System.Text.Encoding.Default.GetString(buffer)
      Dim htmlDom As mshtml.IHTMLDocument2 = New mshtml.HTMLDocument
      htmlDom.write(New Object() {html})

      If htmlDom.links.length > 0 Then
         For elementIndex As Integer = 0 To htmlDom.links.length - 1
            Dim href As String = CType(htmlDom.links.item(Nothing, elementIndex), mshtml.HTMLAnchorElement).href

            If Not String.IsNullOrEmpty(_configSection.InternalDomainName) AndAlso _
               Not href.Contains("//" & _configSection.InternalDomainName) Then

               'Set CSS Class

               Dim className As String = AppendClassName(CType(htmlDom.links.item(Nothing, elementIndex), mshtml.HTMLAnchorElement).className)
               CType(htmlDom.links.item(Nothing, elementIndex), mshtml.HTMLAnchorElement).className = className

               'Append notice to tooltip

               If _configSection.DecorateTooltip Then
                  Dim title As String = AppendTooltip(CType(htmlDom.links.item(Nothing, elementIndex), mshtml.HTMLAnchorElement).title)
                  CType(htmlDom.links.item(Nothing, elementIndex), mshtml.HTMLAnchorElement).title = title
               End If

               'Redirect link to the exit page

               Dim redirectUrl As String = GetRedirectUrl(CType(htmlDom.links.item(Nothing, elementIndex), mshtml.HTMLAnchorElement).href)
               CType(htmlDom.links.item(Nothing, elementIndex), mshtml.HTMLAnchorElement).href = redirectUrl

               'Set target if forceOpen is enabled

               If _configSection.ForceOpenInNewWindow Then _
                  CType(htmlDom.links.item(Nothing, elementIndex), mshtml.HTMLAnchorElement).target = "_blank"
            End If
         Next

         html = System.Text.RegularExpressions.Regex.Replace(html, "<body(.+)</body>", htmlDom.body.outerHTML, _
            RegexOptions.CultureInvariant Or _
            RegexOptions.IgnoreCase Or _
            RegexOptions.Singleline)
      End If

      htmlDom.clear()
      htmlDom = Nothing

      Dim outdata As Byte() = System.Text.Encoding.Default.GetBytes(html)
      _sink.Write(outdata, 0, outdata.GetLength(0))

   End Sub

In the end, I owe this to you...  Thanks...

Pingbacks and trackbacks (2)+

Comments are closed

About the author

Mads Kristensen

Mads Kristensen
Program Manager at the Microsoft Web Platform team and founder of BlogEngine.NET.

More...

Month List

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.