jQuery Printed Footer Links
Monday, March 8. 2010
I was randomly perusing the web and stumbled across an older interesting List Apart article (September 19, 2005 to be exact). In it, the author used JavaScript to create a list of all links found on the page, and then create a footer with a footnote-like list. I was using simple CSS to display the URL of the hyperlink in print display media, but that doesn't work in some browsers (IE), and worse off it can really mess up the visual order of the page.
Inspired by the article's intentions, I decided to use some jQuery to whip up a similar solution and I took the opportunity to use jQuery 1.4's new syntax for object creation (so this is 1.4 code only - see comments for a 1.3.x solution). Differences? I exclude hyperlinks set to the hash symbol (#) which shouldn't be found anyway (graceful degredation people!), "mailto" links, and I don't find link element's citations (blockquote "cite" property). I also believe his script would grab image information, but I'm not entirely sure, mine only searches hyperlinks. I also opted not to exclude listings of duplicate hyperlink values. If it's found twice, it lists it in the footer twice. Less JS processing, and more clear to the visitor (in my opinion).
Expected Issues: It requires JavaScript (and the jQuery library included on your page). If JavaScript is enabled but CSS is disabled, the hidden content will be visible to the user.
On to the code!
First thing's first, we should find the links in our code that we'd like to target. For my situation, I have a content class defined on my page for all content, and the column that contains the actual body is called ".col2_right" (yes, I know, ignore the fact of the poor naming scheme). So, in jQuery, we're going to target all hyperlinks found in the col2_right and content classes, but we don't want to include links to hashes or mailto links. I've also removed listing to nofollow links, but that is my choice (probably not a good one, but I digress).
We'll also need some sort of container to keep these found links wrapped in. I chose to use a fieldset and legend, you could just as easily create a DIV and a H2 or other tags for your own purposes. I also want to create an ordered list to match the found hyperlinks.
Here comes the real center, meaty goodness of the script: looping through our list of found hyperlinks, creating a little notification text next to the hyperlink's text, and add the hyperlink URL itself to the footnote section in the ordered list as a list item.
We use jQuery's each() method to loop through the items in the array, grab the link's URL so that we can do some testing on it, and modify it's value for inclusion in to the footnotes. Some links may be relative URLs, but that doesn't mean much to someone who doesn't know what a relative URL is. In fact, it would probably confuse me too at first. I happen to know that my domain forces www for the subdomain so I've added that in, fix that up as you like. I then create a span tag to hold the associated footnote number (the ListApart article used a superscript tag, I found regular text is more easily readable), add a class to it so it's only visible when printed, and create my list item element with the URL from our link, and place those elements in to the document in the appropriate places with the appendTo jQuery function.
Last but not least, we append our entire footnote to the end of our content body section. The full code is below.
Note the added "if" statement to check the length of the links variable. If it is empty, we did not find any links and don't want to create any extra markup when printing the page.
Oh, and the CSS: ".print_only { display:none; }" This should be placed in your normal style sheet, and leave it out from your print style sheet. If you don't have a print style sheet, extend it a bit: @media print { .print_only { display:none; } }
Note: Thanks to Stiles to provide some fixes and compatibility changes for jQuery 1.3.x.
Inspired by the article's intentions, I decided to use some jQuery to whip up a similar solution and I took the opportunity to use jQuery 1.4's new syntax for object creation (so this is 1.4 code only - see comments for a 1.3.x solution). Differences? I exclude hyperlinks set to the hash symbol (#) which shouldn't be found anyway (graceful degredation people!), "mailto" links, and I don't find link element's citations (blockquote "cite" property). I also believe his script would grab image information, but I'm not entirely sure, mine only searches hyperlinks. I also opted not to exclude listings of duplicate hyperlink values. If it's found twice, it lists it in the footer twice. Less JS processing, and more clear to the visitor (in my opinion).
Expected Issues: It requires JavaScript (and the jQuery library included on your page). If JavaScript is enabled but CSS is disabled, the hidden content will be visible to the user.
On to the code!
First thing's first, we should find the links in our code that we'd like to target. For my situation, I have a content class defined on my page for all content, and the column that contains the actual body is called ".col2_right" (yes, I know, ignore the fact of the poor naming scheme). So, in jQuery, we're going to target all hyperlinks found in the col2_right and content classes, but we don't want to include links to hashes or mailto links. I've also removed listing to nofollow links, but that is my choice (probably not a good one, but I digress).
We'll also need some sort of container to keep these found links wrapped in. I chose to use a fieldset and legend, you could just as easily create a DIV and a H2 or other tags for your own purposes. I also want to create an ordered list to match the found hyperlinks.
Here comes the real center, meaty goodness of the script: looping through our list of found hyperlinks, creating a little notification text next to the hyperlink's text, and add the hyperlink URL itself to the footnote section in the ordered list as a list item.
We use jQuery's each() method to loop through the items in the array, grab the link's URL so that we can do some testing on it, and modify it's value for inclusion in to the footnotes. Some links may be relative URLs, but that doesn't mean much to someone who doesn't know what a relative URL is. In fact, it would probably confuse me too at first. I happen to know that my domain forces www for the subdomain so I've added that in, fix that up as you like. I then create a span tag to hold the associated footnote number (the ListApart article used a superscript tag, I found regular text is more easily readable), add a class to it so it's only visible when printed, and create my list item element with the URL from our link, and place those elements in to the document in the appropriate places with the appendTo jQuery function.
Last but not least, we append our entire footnote to the end of our content body section. The full code is below.
Note the added "if" statement to check the length of the links variable. If it is empty, we did not find any links and don't want to create any extra markup when printing the page.
Oh, and the CSS: ".print_only { display:none; }" This should be placed in your normal style sheet, and leave it out from your print style sheet. If you don't have a print style sheet, extend it a bit: @media print { .print_only { display:none; } }
Note: Thanks to Stiles to provide some fixes and compatibility changes for jQuery 1.3.x.
Trackbacks
Trackback specific URI for this entry
No Trackbacks

Comments
First, lines like
I had to change to
Also, the original selector to find the links on the page would pick up anchors which did not have an href defined (there was no href="" inside the a tag). Then later in the code, when you check the first character of the href (linkValue.substring(0,1) === '/') javascript throws an error because href is undefined. To fix this, I changed
to
After these minor changes, it's working great! Thanks again.
Ironically, I made the exact same change to someone else's script 2 days before (a[href]) and didn't put it in this code, I have no idea why. I'll be updating the code for the anchor without an href property, as well as mentioning this works for jQuery 1.4+. Thank you for your comment!
I've also updated the full code block and added in an "if" statement. You've probably already done this, but thought I would bring it up.
1. I have a print stylesheet that puts the href after any links (i.e., a:link:after{etc..}) -- I've been using this for a while successfully.
2. I load the jquery library from an external file.
3. I take the "full code" (last snippet) from above and either reference it externally or put it inline in my page -- and I alter it so that the container we're searching is correctly named.
I've done all this but nothing. What am I missing?
2 & 3: Yes and yes.
It's hard to say without seeing a live example of it not working. Do you have a location with it online and live that I could see?
...also, remove the "www" in the "http://www" + document.location.host line...that was an oversight of mine, and I've edited the code as such.
[url=http://www.chabun.com/blog/post/2009/04/05/Using-wget-to-keep-your-website-alive.aspx]http://www.chabun.com/blog/...[/a]
The scripts are just before the closing form tag, one to jquery, and then inline script with your code.
thanks for looking at this.
I don't know what's wrong on that page that I sent you. The css validates, I'm validating the html now. Then I'm going to try simplifying the blog theme I modified. I had grabbed it from someone and just changed a couple colours. However, your solution worked for me in a simple page doing as I described in my first post:
http://www.chabun.com/blog/themes/chabun/test.html
So, I'll muddle along and figure it out (unless you really have time to look at my page ... which is far more than I expect).
Thanks for your help.
That is the problem; I haven't yet looked through to find exactly what the problem is, but a quick solution would be to forcibly show the footnote area, and the referencing numbers (in your current version of the code, the SUP tags).
In the print style sheet:
.print_only { display:inline; }
fieldset.print_only { display:block; }
That should (hopefully) fix the visibility issues you're having; though I doubt it's the best solution; and there may be others wandering around.
In your example, you'd probably also want to disallow links that contain "javascript:[...]" from being rendered in the footnote area. :)
(...and you did it without my overbearing CSS band-aid fix.)