MooTools & Printing – Creating a Links Table of Contents

By  on  

One detail we sometimes forget when considering print for websites is that the user cannot see the URLs of links when the page prints. While showing link URLs isn't always important, some websites could greatly benefit from doing so. This tutorial will show you how to create a dynamic link table of contents using MooTools and basic CSS.

The XHTML

<div id="print-content-area">
	<p class="large">MooTools is a <em>compact</em>, <em>modular</em>, <em>Object-Oriented</em> JavaScript framework designed for the intermediate to advanced JavaScript developer. It allows you to write <em>powerful</em>, <em>flexible</em>, and <em>cross-browser</em> code with its elegant, well documented, and <em>coherent API</em>.</p>
	<p class="quiet">MooTools code respects strict standards and doesn't throw any warnings. It's extensively documented and has meaningful variable names: a joy to browse and a snap to understand.</p>
	<div class="block span-8 colborder">
		<h3 class="red"><span>Open Source License</span></h3>
		<p>MooTools is released under the Open Source <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>, which gives you the possibility to use it and modify it in every circumstance. </p>
	</div>
	<div class="block span-8 last">
		<h3 class="green"><span>Browser Compatibility</span></h3>
		<p>MooTools is compatible and fully tested with <a href="http://apple.com/safari/">Safari 2+</a>, Internet Explorer 6+, <a href="http://mozilla.com/">Firefox 2+</a> (and browsers based on gecko), <a href="http://opera.com/">Opera 9+</a>.</p>
	</div>
	<div id="thebook" class="block span-8 colborder">
		<h3 class="blue">The MooTools Book</h3>
		<p>Pick up a copy of <a href="http://www.amazon.com/MooTools-Essentials-JavaScript-Development-Firstpress/dp/1430209836">MooTools Essentials</a> from <a href="http://clientside.cnet.com">Aaron Newton</a>, published by <a href="http://apress.com">Apress</a></p>
	</div>
	<div id="links" class="block span-8 last">
		<h3 class="purple"><span>Some applications using MooTools</span></h3>
		<p>
			<a href="http://www.macheist.com/" class="macheist">macheist</a>
			<a href="http://validator.w3.org/" class="w3c">w3c</a>
			<a href="http://cnet.com/" class="cnet">cnet</a>
			<a href="http://joomla.org/" class="joomla">joomla</a>
			<a href="http://quizlet.com/" class="quizlet">quizlet</a>
			<a href="http://vimeo.com/" class="vimeo">vimeo</a>
			<a href="http://powerset.com" class="powerset">powerset</a>
			<a href="http://ubuntu.com/" class="ubuntu">ubuntu</a>
			<a href="http://gamespot.com/" class="gamespot">gamespot</a>
			<a href="http://tv.com/" class="tvdotcom">tv.com</a>
			<a href="http://www.chrysler.com" class="chrysler">chrysler</a>
			<a href="http://www.jeep.com" class="jeep">jeep</a>
			<a href="http://parisenvies.com/" class="parisenvies">paris envies</a>
			<a href="http://netvibes.com/" class="netvibes">netvibes</a>
		</p>
	</div>
</div>

Obviously we don't need to record the links within the navigation menu, header, footer, etc. because they don't have print value (and should be hidden in your stylesheet anyway). I've wrapped the valuable content with a DIV to help us identify that it's important. The sample content has been duplicated from the MooTools homepage.

The CSS

@media all {
	.print-only { display:none; }
}
@media print {
	span.print-only { display:inline; font-size:10px; padding-left:5px; }
	.toc-list	{ page-break-before:always; display:block; padding-left:35px; font-size:10px; }
}

There's very little CSS needed. Obviously the print-only class hides elements we inject so that the user cannot see them on their screen. Be sure to style the toc-list however you'd like.

The MooTools JavaScript

/* when the dom is ready */
window.addEvent('domready',function() {
	/* get the links */
	var links = $$('#print-content-area a');
	/* if there are any */
	if(links.length) {
		/* create toc list */
		var container = new Element('ol',{
			'class': 'print-only toc-list'
		}).inject(document.body,'bottom');
		/* add a heading for the TOC */
		var header = new Element('h2',{
				text: 'Links In This Document'
		}).inject(container,'top');
		/* get links inside the content area */
		links.each(function(a,i) {
			if(a.get('href')){
				/* insert the span reference right after the link */
				new Element('span',{
					text: '[' + (i + 1) + ']',
					'class': 'print-only'
				}).inject(a,'after');
				/* record anchor, put in list */
				new Element('li',{
					text: a.get('href')
				}).inject(container,'bottom');
			}
		});
	}
});

We dynamically tack on another DIV which will be placed on a separate printed page. We add a heading, create a list, and inject all of the links into that list.

You can achieve a similar effect using pure CSS but it wont work in Internet Explorer 6 while the above will. Happy mooing!

Recent Features

  • By
    CSS vs. JS Animation: Which is Faster?

    How is it possible that JavaScript-based animation has secretly always been as fast — or faster — than CSS transitions? And, how is it possible that Adobe and Google consistently release media-rich mobile sites that rival the performance of native apps? This article serves as a point-by-point...

  • By
    Conquering Impostor Syndrome

    Two years ago I documented my struggles with Imposter Syndrome and the response was immense.  I received messages of support and commiseration from new web developers, veteran engineers, and even persons of all experience levels in other professions.  I've even caught myself reading the post...

Incredible Demos

Discussion

  1. Simple but highly useful! I love it! Oh wait…I wrote it. David Walsh and MooTools FTW!

  2. deef

    Nice feature!

    David, your Sugar & Style Ajax loader is driving me bananas… I keep waiting for it to load.

  3. Isn’t it faster to create the link list via php? Just select the links with a preg_match_all and insert it at the bottom of the page… I’ll make a quick example soon!

  4. Sara

    This is great, except that the part of the page I want to show links from also includes some named anchors for internal page navigation. These show up as blanks in the list of links, since they lack the href attribute. Is there someway to prevent the inclusion of these named anchors in the list of links?

  5. Sara

    I came up with my own solution:

    /* when the dom is ready */
    window.addEvent('domready',function() {
    	/* get the links */
    	var links = $$('#print-content-area a');
    	
    	/* remove from the array named anchors lacking an "href" property */
    	function notNull(a) {
    		return(a.get('href') != undefined);
    	}
    	var filteredLinks = links.filter(notNull);
    
    	/* if there are any */
    	if(filteredLinks.length) {
    		/* create toc list */
    		var container = new Element('ol',{
    			'class': 'print-only toc-list'
    		}).inject(document.body,'bottom');
    		/* add a heading for the TOC */
    		var header = new Element('h2',{
    				text: 'Links In This Document'
    		}).inject(container,'top');
    		/* get links inside the content area */
    		filteredLinks.each(function(a,i) {
    			/* insert the span reference right after the link */
    			/*if(a.get('href') != undefined){*/
    				new Element('span',{
    					text: '[' + (i + 1) + ']',
    					'class': 'print-only'
    				}).inject(a,'after');
    				/* record anchor, put in list */
    				new Element('li',{
    					text: a.get('href')
    				}).inject(container,'bottom');
    			/*}*/
    		});
    	}
    });
    

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!