Improving Link Display for Print

When I was nearing completion of my ultimate article, I printed a reproduction of it for my partner, Kelly, to proofread. As it used to be as soon as a piece of writing for newsletter online, I had written it in HTML and printed it from the check out server, profiting from my trusty print style sheet to make it look correct.

A few internet web page in, Kelly let free an frustrated sigh and posited “How do you expect me to be told this with all of the ones URLs throughout the entire thing?” It appeared my zeal for linkage had come into warfare with my wish to strengthen print usability.

What’s a developer/husband to do? Restore it, in reality. And so I commit this text to Kelly: would most likely she continue to proofread my articles unimpeded.

Eric Meyer’s printed internet web page#section1

Many moons prior to now, Eric Meyer wrote a ground-breaking article for A File Apart, by which he offered up rather CSS2 nugget:

a:link:after, a:visited:after {   content material subject matter: " (" attr(href) ") ";   font-size: 90%; }

The use of this rule in a print style sheet will objective any browser that understands CSS2 (Mozilla & Netscape, at the time, and most the entire thing alternatively IE at the time of newsletter, although we are recommended the impending IE7 will beef up generated content material subject matter) to insert the cost of an anchor’s href function, in-line, after the text, fairly smaller and flanked by way of parentheses:

Improving Link Display for Print

This is extraordinarily helpful for purchasers who print the internet web page, as it signs them to the holiday spot of each and every link. In case you have a paragraph with numerous links (in particular long ones), alternatively, this system hinders readability:

Improving Link Display for Print

We will’t have that.

The plan#section2

Having spent a couple of years in academia and publishing, I’m partial to footnotes/endnotes. They are a standard convention in print, so it seems natural to transport in that route. Following this line of considering, our targets might be to:

  • collect all of the URIs referenced (hrefs and citations) in a decided on container within the internet web page (after all, we in all probability don’t want to snatch the navigation, and so forth.),
  • place the links (minding the duplicates) into an ordered tick list which will also be dropped into an id-ed container of our choosing, and
  • supply each and every reference with the corresponding footnote amount as a superscript.

Luckily, all of this is neatly within our snatch when we get right to use the DOM by way of JavaScript.

The script#section3

Quicker than we start scripting, we will have to outline detailed directions for ourselves throughout the code:

function footnoteLinks() {   // get the container and objective // create a heading for the footnotes    // create an <ol> to contain the footnotes    // create an array to store used links    // so we can take a look at for duplicates    // create a variable to stick practice of the amount used for each and every      // link, so we have it for footnote references    // collect all of the portions throughout the specified container into an array    // cycle throughout the portions in that array,   // in search of hrefs and citations   // if a duplicate   // get the corresponding amount from the array of used links   // if not a duplicate   // assemble the <li> and append to the <ol>   // store the link throughout the array  // increment the amount variable   // assemble the <sup> and append after the reference   // append the heading and <ol> to the target }

This offers a gorgeous forged foundation, so let’s get development. We’ll tackle each and every procedure one after the other, starting by way of examining the function itself. We need to move it two variables: one for the id of container we are grabbing the URIs from (containerID) and one for the id of the target container for our footnotes (targetID):

function footnoteLinks(containerID,targetID) {

Now that we’ve added those arguments, we can quickly identify those containers in our script:

// get the container & objective var container = record.getElementById(containerID); var objective    = record.getElementById(targetID);

This may increasingly most probably make problems much more sensible in a while.

The heading for our content material subject matter is up next. As we want it (along with the rest of our generated markup) to show up in print most effective, we’ll class it “printOnly” (we’ll write the CSS rule for this later):

// create a heading for the footnotes var h2     = record.createElement('h2'); addClass.follow(h2,['printOnly']); var h2_txt = record.createTextNode('Links'); h2.appendChild(h2_txt);

[Phrase: we are applying the addClass() function from the Easy! Designs jsUtilities package deal to class our portions.]

Now we can create our ordered tick list and those variables we need to be in agreement us keep practice of what’s going down:

// create an <ol> to contain the footnotes var ol = record.createElement('ol'); addClass.follow(ol,['printOnly']);// create an array to store used links // so we can take a look at for duplicates var myArr = []; // to store all the links var thisLink;   // to store each and every link in my view // create a variable to stick practice of the amount used for each and every   // link, so we have it for footnote references var num = 1;

Now for the heavy lifting. We need to iterate by the use of all of the portions throughout the container, in search of href and cite attributes. It is excellent to note that all the way through XHTML 2.0 we can make anything a link and we can already put a cite function on just about anything, not merely <resolve class="quote"><blockquote>s and <q>s, so we will have to not limit ourselves to only accumulating anchors, block quotes and inline quotations:

// collect all of the portions throughout the specified container into  // an array var coll = container.getElementsByTagName('*');

Now we can loop by the use of that collection, in search of href and cite attributes:

// cycle throughout the portions in that array, in search of hrefs  // and citations for (var i=0; i<coll.period; i++) {   // take a look at for our attributes   if ( coll<i>.getAttribute('href') ||     coll<i>.getAttribute('cite') ) {   // snatch the reference     thisLink = coll<i>.getAttribute('href') ? coll<i>.href      : coll<i>.cite;

That looks excellent so far. Now we need to create our superscript:

 // assemble the <sup> and append after the reference   var phrase = record.createElement('sup');   addClass.follow(phrase,['printOnly']);

We’re going to suppose each and every URI reference shall be unique for now, revisiting the script later to check for duplicates:

 var note_txt = record.createTextNode(num);   phrase.appendChild(note_txt);

We’re moreover going to suppose we are dealing with anything alternatively blockquoted text for now, and we’ll append the reference inline previous to the referencing element’s next sibling:

 coll<i>.parentNode.insertBefore(phrase, coll<i>.nextSibling);

We create a list products to contain the URI and then push that URI to the in a position array (so we can use it to reference duplicates):

 // assemble the <li> and append to the <ol>     var li     = record.createElement('li');     var li_txt = record.createTextNode(thisLink);     li.appendChild(li_txt);     ol.appendChild(li);     // store the link throughout the array     myArr.push(thisLink);

[Phrase: not all browsers natively beef up the push approach, alternatively you’ll be able to be in agreement such unfortunate browsers deal by way of writing a script to stipulate the method for them. It is usually available throughout the jsUtilities package deal.]

Now we increment our amount to prepare for the next reference and close the loop:

   // increment the amount variable     num++;   }

In any case, we append our heading and tick list to the target:

 objective.appendChild(h2);   objective.appendChild(ol); }

We now have were given rather tidying up to do previous to we wrap the script. First of all, we need to care for copy URI references. We accomplish this by way of looking by the use of that array (myArr) we created for keeping track of our used URIs. We will do that with the JavaScript port of PHP’s inArray function (moreover available throughout the jsUtilities package deal). inArray turns out for a value (needle) in regardless of array (haystack) we apply it to and returns “true” (with the index worth) if came upon and “false” if not came upon. We use it when we are looping throughout the collection:

for (var i=0; i<coll.period; i++) {   if ( coll<i>.getAttribute('href') ||      coll<i>.getAttribute('cite') ) {      thisLink = coll<i>.getAttribute('href') ? coll<i>.href        : coll<i>.cite;     var phrase = record.createElement('sup');     addClass.follow(phrase,['printOnly']);     var note_txt;     var j = inArray.follow(myArr,[thisLink]);     if ( j || j===0 ) { // if a duplicate       // get the corresponding amount from the array of        // used links       note_txt = record.createTextNode(j+1);     } else { // if not a duplicate       // assemble the <li> and append to the <ol>       var li     = record.createElement('li');       var li_txt = record.createTextNode(thisLink);       li.appendChild(li_txt);       ol.appendChild(li);       // store the link throughout the array       myArr.push(thisLink);       note_txt = record.createTextNode(num);       // increment the amount variable       num++;       }     phrase.appendChild(note_txt);     …   } }

Throughout the snippet above, we want to see if thisLink is positioned in myArr and then coping with the superscript accordingly. If thisLink is positioned (j is “true”), we make the superscript j+1 (as array indexing starts at 0 and ordered lists get began at 1) and we’re completed. If thisLink is not came upon (j is “false”), we need to create the tick list products for the reference, append it to the <ol>, push thisLink to myArr, and create our superscript reference (incrementing num afterwards). You will need to phrase that, as inArray returns the array index, the cost of j could be 0 if it is the first products throughout the array. JavaScript will interpret this as false if we have been to use the “is equal to” operator (j==0), so we use the “is identical to” operator (j===0) so to pick up duplication of the principle URI reference in a given internet web page.

The next step in tidying-up involves together with our reference in block-level portions. If you are making a block-level quote of a couple of sort, to be if truth be told semantic, it will have to be in a <resolve class="quote"<>blockquote<. Your <resolve class="quote"<>blockquote> would possibly simply contain any type of block-level element, most ceaselessly paragraphs (<p>) and lists (<ul>, <ol>, <dl>). Being that we might want to have our reference superscript appear at the end of the general line of text (to care for now not strange typographic style), we need to to search out the general child of the <resolve class="quote"<>blockquote> which is a text-containing block-level element. We will accomplish this with the function lastChildContainingText (you guessed it, in jsUtilities):

function footnoteLinks(containerID,targetID) {   …   if (coll<i>.tagName.toLowerCase() == 'blockquote') {     var lastChild = lastChildContainingText.follow(coll<i>);     lastChild.appendChild(phrase);   } else {     coll<i>.parentNode.insertBefore(phrase, coll<i>.nextSibling);   }   … }

In any case, we can round out our script by way of making it degrade gracefully in browsers that don’t beef up the methods we use in this function…

function footnoteLinks(containerID,targetID)        !record.getElementsByTagName 

…and in pages that contain neither our objective nor container portions:

function footnoteLinks(containerID,targetID)        !record.createElement) return false;   if (!record.getElementById(containerID) 

Now, we simply set the function to run on internet web page load.

window.onload = function() {   footnoteLinks('container','container'); }

Then we create a method for .printOnly in our show style sheet…

.printOnly {   display: none; }

…and you’ll be able to see the finished product.

Contingencies#section4

This process, in reality, assumes JavaScript is available for use, alternatively what if it isn’t? To take this into account, we can keep Eric’s content material subject matter generation CSS intact, the use of that as a fall-back to our script, and eliminating it when the script runs successfully.

This is completed by way of keeping the original CSS declarations for generating the href content material subject matter and then, when the script runs, we class-ify <html> as “well-known.” We then add a rule to our print style sheet to disable the content material subject matter generation when the links in question are descendants of html.well-known:

html.well-known a:link:after, html.well-known a:visited:after {   content material subject matter: ""; }

Wrapping up#section5

So there you have got it, a delightful, clean, printable record with all links and citations accrued into footnotes. Use it, revel in it, and strengthen on it. For example, it’s a must to add throughout the talent to omit about specific links classed as “omit about.” Get creative and let us know what you come up with.

You are able to download the latest compressed style of footnoteLinks from its homepage or download the running knowledge for this text from this internet website online. All of the JavaScript prototypes used in this article are contained in jsUtilities 2.1, which is available as a compressed download from its homepage.

You’ve “moved rapid and broken problems.” Proper right here’s some helpful advice from Jeremy Wagner to fix them responsibly. A key facet of being a manager is helping your research be triumphant. Lara Hogan shares how in this excerpt from Resilient Keep an eye on. Abruptly, I noticed that the people next to me could be considerably impacted by way of my artwork. I was having a at hand information a coarse lunch throughout the airport… Retraining slim assumptions about consumers’ gender identities is a step in opposition to better coverage, privacy, and validation for everyone. In this excerpt from Regularly Knowledge Construction, Lisa Maria Martin introduces the structural audit.