Print out HREFs on Links for Print StyleSheet

So there's the problem: there's a cool bit of CSS that instructs the browser to display a link's URL after it like this:

... when I found this great recipe for a cocktail called Drunk Monkey [http://www.drinksmixer.com/drink9097.html] that we tried out in Cambodia. ...

The CSS that's used to create this in your Style Sheet is pretty simple

	a:after { content: " [" attr(href) "] " }

This feature is perfect for Print Style Sheets where there was previously no other way for users to see where the links on their printed page went to (at least not without a whole heap of sever-side scripting or special Print Pages - yuck!).

Unfortunately, MSIE doesn't implement this style rule and while FireFox is forging ahead in it's bid for more market share, 7.4% means that we still need to look out for IE users. So here's some code that replicates that functionality for all browsers.

An additional bonus that this script has over the CSS is that it provides more flexibility. The current CSS implementation is to make the text a part of the link element itself. Using the DOM, the code below creates the text after the link as a whole new element (and even assigns it a class name). This means you can style it any way you want. So let's have a look at the code...

01  function showHREF() {
02     if (document.getElementsByTagName) {
03        onlyContentLinks = document.getElementById("content");
04        whichLink = onlyContentLinks.getElementsByTagName("a");
05        for (var i=0; i<whichLink.length; i++) {
06           useLink = whichLink[i];
07           showLink = useLink.getAttribute("href")
08
09           if (useLink.getAttribute("rel") != "external") {
10              if (showLink.substring(0,7) == "mailto:") {
11                 showLink = showLink.substring(7,lastSlash);
12              } else {
13                 checkShow = showLink.lastIndexOf("/");
14                 showLink = showLink.substring(checkShow+1,showLink.length);
15
16                 lastSlash = document.location.href.lastIndexOf("/");
17                 directory = document.location.href.substring(0,lastSlash);
18
19                 showLink = directory + '/' + showLink;
20              }
21           }
22
23           newSpan = document.createElement("span");
24           showTitle = document.createTextNode(' [' + showLink + ']');
25           newSpan.appendChild(showTitle);
26           useLink.parentNode.insertBefore(newSpan,useLink.nextSibling);
27           newSpan.className='printLink';
28        }
29     }
30  }
31  window.onload = showHREF();

Download

You can view/download the script here.

Examples

UPDATE! Challenged by Randy P to come up with something based on this script that acted more like a footnote, I've put together this example page that does exactly that. All generated code is output as semantic XHTML at the bottom of the page. This is really cool if you have an article and want to have a set of references at the bottom (like Digital-Web). Check out how I made Footnotes Made From Links.

Screen Example

... when I found this great recipe for a cocktail called Drunk Monkey that we tried out in Cambodia. ... Submitted by Richard

Print Example

... when I found this great recipe for a cocktail called Drunk Monkey that we tried out in Cambodia. ... Submitted by Richard

Print Example (Alternative)

... when I found this great recipe for a cocktail called Drunk Monkey that we tried out in Cambodia. ... Submitted by Richard

Explanation

Line: 01
Start Function
Line: 02
Test if the browser can handle DOM stuff. If it can't then nothing happens. This allows us to have a gracefully degrading script.
Line: 03
This line sets onlyContentLinks as a variable. It references the <DIV> in my page's code with an ID of "content". This is because I only really want this function to work for the links in the contents section of the page (and not the 80 links in my navigation!).
Line: 04
whichLink is variable, calling for all the links in the 'content' section.
Line: 05
Let's loop through all the links.
Line: 06
The variable useLink is just easier to use and stops us from making silly mistakes with the [i].
Line: 07
showLink is assigned the value of each link's HREF by using the DOM's oh-so-handy getAttribute.
Line: 08
empty line
Line: 09
OK. From Line 09 to Line 18: this is here purely for the perfectionists. If you're worried about code bulk, simply delete these lines. Here's what they do...

As it stands, the script will simply add the HREF of the link. If your link is to a page within your own site, then all FireFox will show is that page's file name (eg: printLinkURLs.html). MSIE will do the nice thing and print the whole URL regardless of whether it's an internal link or an external link (eg: http://www.drunkmonkey.com.au/printLinkURLs.html). These lines make all browsers do what MSIE does.

Line 09 depends on you using rel="external" for all links pointing to pages not on your domain - which you should if you're writing XHTML. If you're using the good ol' target="_blank", don't despair. Simple replace Line 09 with this code:

if (useLink.getAttribute("target") != "_blank") {

Rikkert Koppes rightly pointed out that opening external links in a new window is optional. Too true! If that's the case, then I suggest testing the opening 5 letters of the URL to check if they're "http:". This'll do the job as well. - Thanks, Rikkert for pointing this out.

Personally, there are a lot of problems with this part of the script (relative URLs, etc...) and I haven't really had time to nut it out. Realistically, this section of the code (Lines 09-18) was designed for the way I like to have external links and my file structure, rather than a universal application - so use at your own risk.   :o)
Line: 10
Checks to see if the link is an Email Address (suggested by Christian Sørensen)
Line: 11
Strips off the "mailto:" part of the link - leaving a nice clean email address
Line: 12
Close the Email Address part of this function
Line: 13
Because MSIE will show the full path we have to crop it first. This line gets the last "/" in the URL.
Line: 14
This cuts off everything before the last "/", including the last "/". Now we have the file name (eg: printLinkURLs.html). This has leveled the playing field for all browsers. Now we just need to get the whole URL...
Line: 15
empty line
Line: 16
Get's the domain of your site and finds the last "/".
Line: 17
Then cuts off everything after it, leaving us with the domain path.
Line: 18
empty line
Line: 19
Our complete URL for internal pages, with domain path and filename
Line: 20
Close the Web Address part of this function
Line: 21
Close this painful procedure!
Line: 22
empty line
Line: 23
Back to the cool part of the script. We get the DOM to create a new element, in this case a span.
Line: 24
Then the DOM creates the contents of the span. I've elected to put the HREF in square brackets [ ... ]. The HREF is inserted using the variable showLink we created in Line 07.
Line: 25
We then plug the contents into span.
Line: 26
By referencing the parent of the link, we get the DOM to insert the span before the element directly after the link. It would be **really** nice if there was a DOM Method called insertAfter, but c'est la vie!
Line: 27
Now we assign a class name to the span (in this case, printLink). Remember: put this class in both your screen Style Sheet (probably with display: none;) and in your print Style Sheet with any styling you like!
Line: 28
Close the loop started in Line 05.
Line: 29
Close test for DOM-friendliness started in Line 02.
Line: 30
Close Function
Line: 31
Calls the function after the page has loaded. This is necessary as, obviously, we need the page to load the links as well as the container <DIV>. If you have other JavaScripts in your external file that also get called onload, then you may want to use a single script to load all of these together. See Below.

Multiple OnLoads

Delete Line 26 above and add this to the bottom of your external JS file. Don't forget to remove lines04 and 05 below as they are just for demonstration purposes.

01  // Multiple Onload Functions to be called
02  function multipleOnload() {
03    showHREF();
04    anotherFunction();
05    andAnotherFunction();
06  }
07  window.onload = multipleOnload;

All comments/suggestions welcome! Please email me at

Cheers!   :o)
Richard