Enhancing Hyperlink Show for Print – A Listing Aside

After I was nearing completion of my final article, I printed a replica of it for my spouse, Kelly, to proofread. Because it was an article for publication on-line, I had written it in HTML and printed it from the check server, making the most of my trusty print model sheet to make it look proper.

Article Continues Under

A few web page in, Kelly set free an irritated sigh and posited “How do you anticipate me to learn this with all of those URLs in the course of the whole lot?” It appeared my zeal for linkage had come into battle with my need to enhance print usability.

What’s a developer/husband to do? Repair it, in fact. And so I dedicate this text to Kelly: could she proceed to proofread my articles unimpeded.

Eric Meyer’s printed web page#section2

Many moons in the past, Eric Meyer wrote a ground-breaking article for A Listing Aside, by which he supplied up just a little CSS2 nugget:

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

Utilizing this rule in a print model sheet will trigger any browser that understands CSS2 (Mozilla & Netscape, on the time, and most the whole lot however IE on the time of publication, although we’re instructed the forthcoming IE7 will assist generated content material) to insert the worth of an anchor’s href attribute, in-line, after the textual content, barely smaller and flanked by parentheses:

A sample of generated contentent from one link in a paragraph.

That is extremely useful for customers who print the web page, because it alerts them to the vacation spot of every hyperlink. When you will have a paragraph with plenty of hyperlinks (particularly lengthy ones), nevertheless, this method hinders readability:

A sample of generated contentent from many links in a paragraph.

We will’t have that.

Having spent a few years in academia and publishing, I’m a fan of footnotes/endnotes. They’re a normal conference in print, so it appears pure to go in that course. Following this line of considering, our goals can be to:

  • acquire all the URIs referenced (hrefs and citations) in a selected container inside the web page (in spite of everything, we in all probability don’t wish to seize the navigation, and many others.),
  • place the hyperlinks (minding the duplicates) into an ordered checklist which will be dropped into an id-ed container of our selecting, and
  • provide every reference with the corresponding footnote quantity as a superscript.

Fortunately, all of that is properly inside our grasp after we entry the DOM by way of JavaScript.

Earlier than we begin scripting, we should always define detailed instructions for ourselves within the code:

operate footnoteLinks() {
  // get the container and goal // create a heading for the footnotes 
  // create an <ol> to include the footnotes 
  // create an array to retailer used hyperlinks 
  // so we are able to test for duplicates 
  // create a variable to maintain observe of the quantity used for every   
  // hyperlink, so we now have it for footnote references 
  // acquire all the components within the specified container into an array 
  // cycle by way of the weather in that array,
  // on the lookout for hrefs and citations
  // if a replica
  // get the corresponding quantity from the array of used hyperlinks
  // if not a replica
  // construct the <li> and append to the <ol>
  // retailer the hyperlink within the array  // increment the quantity variable
  // construct the <sup> and append after the reference
  // append the heading and <ol> to the goal
}

This gives a fairly stable basis, so let’s get constructing. We’ll sort out every job individually, beginning by analyzing the operate itself. We have to go it two variables: one for the id of container we’re grabbing the URIs from (containerID) and one for the id of the goal container for our footnotes (targetID):

operate footnoteLinks(containerID,targetID) {

Now that we’ve added these arguments, we are able to shortly establish these containers in our script:

// get the container & goal
var container = doc.getElementById(containerID);
var goal    = doc.getElementById(targetID);

It will make issues a lot easier afterward.

The heading for our content material is up subsequent. As we would like it (in addition to the remainder of our generated markup) to point out up in print solely, we’ll class it “printOnly” (we’ll write the CSS rule for this later):

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

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

Now we are able to create our ordered checklist and people variables we have to assist us maintain observe of what’s occurring:

// create an <ol> to include the footnotes
var ol = doc.createElement('ol');
addClass.apply(ol,['printOnly']);// create an array to retailer used hyperlinks
// so we are able to test for duplicates
var myArr = []; // to retailer all of the hyperlinks
var thisLink;   // to retailer every hyperlink individually
// create a variable to maintain observe of the quantity used for every 
 // hyperlink, so we now have it for footnote references
var num = 1;

Now for the heavy lifting. We have to iterate by way of all the components within the container, on the lookout for href and cite attributes. It’s good to notice that in XHTML 2.0 we will make something a hyperlink and we are able to already put a cite attribute on nearly something, not simply <determine class="quote"><blockquote>s and <q>s, so we should always not prohibit ourselves to solely gathering anchors, block quotes and inline quotations:

// acquire all the components within the specified container into 
// an array
var coll = container.getElementsByTagName('*');

Now we are able to loop by way of that assortment, on the lookout for href and cite attributes:

// cycle by way of the weather in that array, on the lookout for hrefs 
// and citations
for (var i=0; i<coll.size; i++) {
  // test for our attributes
  if ( coll<i>.getAttribute('href') ||
    coll<i>.getAttribute('cite') ) {
  // seize the reference
    thisLink = coll<i>.getAttribute('href') ? coll<i>.href 
    : coll<i>.cite;

That appears good up to now. Now we have to create our superscript:

 // construct the <sup> and append after the reference
  var notice = doc.createElement('sup');
  addClass.apply(notice,['printOnly']);

We’re going to imagine every URI reference can be distinctive for now, revisiting the script later to test for duplicates:

 var note_txt = doc.createTextNode(num);
  notice.appendChild(note_txt);

We’re additionally going to imagine we’re coping with something however blockquoted textual content for now, and we’ll append the reference inline earlier than the referencing ingredient’s subsequent sibling:

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

We create an inventory merchandise to include the URI after which push that URI to the ready array (so we are able to use it to reference duplicates):

 // construct the <li> and append to the <ol>
    var li     = doc.createElement('li');
    var li_txt = doc.createTextNode(thisLink);
    li.appendChild(li_txt);
    ol.appendChild(li);
    // retailer the hyperlink within the array
    myArr.push(thisLink);

[Note: not all browsers natively support the push method, but you can help such unfortunate browsers deal by writing a script to define the method for them. It is also available in the jsUtilities package.]

Now we increment our quantity to arrange for the subsequent reference and shut the loop:

   // increment the quantity variable
    num++;
  }

Lastly, we append our heading and checklist to the goal:

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

We’ve just a little tidying as much as do earlier than we wrap the script. To start with, we have to deal with duplicate URI references. We accomplish this by wanting by way of that array (myArr) we created for retaining observe of our used URIs. We will do this with the JavaScript port of PHP’s inArray operate (additionally out there within the jsUtilities package deal). inArray seems for a worth (needle) in no matter array (haystack) we apply it to and returns “true” (with the index worth) if discovered and “false” if not discovered. We use it after we are looping by way of the gathering:

for (var i=0; i<coll.size; i++) {
  if ( coll<i>.getAttribute('href') || 
    coll<i>.getAttribute('cite') ) { 
    thisLink = coll<i>.getAttribute('href') ? coll<i>.href 
      : coll<i>.cite;
    var notice = doc.createElement('sup');
    addClass.apply(notice,['printOnly']);
    var note_txt;
    var j = inArray.apply(myArr,[thisLink]);
    if ( j || j===0 ) { // if a replica
      // get the corresponding quantity from the array of 
      // used hyperlinks
      note_txt = doc.createTextNode(j+1);
    } else { // if not a replica
      // construct the <li> and append to the <ol>
      var li     = doc.createElement('li');
      var li_txt = doc.createTextNode(thisLink);
      li.appendChild(li_txt);
      ol.appendChild(li);
      // retailer the hyperlink within the array
      myArr.push(thisLink);
      note_txt = doc.createTextNode(num);
      // increment the quantity variable
      num++;
      }
    notice.appendChild(note_txt);
    …
  }
}

Within the snippet above, we wish to see if thisLink is present in myArr after which dealing with the superscript accordingly. If thisLink is discovered (j is “true”), we make the superscript j+1 (as array indexing begins at 0 and ordered lists begin at 1) and we’re finished. If thisLink shouldn’t be discovered (j is “false”), we have to create the checklist merchandise for the reference, append it to the <ol>, push thisLink to myArr, and create our superscript reference (incrementing num afterwards). You will need to notice that, as inArray returns the array index, the worth of j may very well be 0 if it’s the first merchandise within the array. JavaScript will interpret this as false if we have been to make use of the “is the same as” operator (j==0), so we use the “is an identical to” operator (j===0) to have the ability to decide up duplication of the primary URI reference in a given web page.

The following step in tidying-up includes including our reference in block-level components. If you’re making a block-level quote of some type, to be really semantic, it must be in a <determine class="quote"<>blockquote<. Your <determine class="quote"<>blockquote> might include any sort of block-level ingredient, mostly paragraphs (<p>) and lists (<ul>, <ol>, <dl>). Being that we’d wish to have our reference superscript seem on the finish of the final line of textual content (to take care of frequent typographic model), we have to discover the final baby of the <determine class="quote"<>blockquote> which is a text-containing block-level ingredient. We will accomplish this with the operate lastChildContainingText (you guessed it, in jsUtilities):

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

Lastly, we are able to spherical out our script by making it degrade gracefully in browsers that don’t assist the strategies we use on this operate…

operate footnoteLinks(containerID,targetID) 
      !doc.getElementsByTagName 

…and in pages that include neither our goal nor container components:

operate footnoteLinks(containerID,targetID) 

Now, we merely set the operate to run on web page load.

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

Then we create a mode for .printOnly in our display model sheet…

.printOnly {
  show: none;
}

…and you’ll see the completed product.

This course of, in fact, assumes JavaScript is obtainable to be used, however what if it isn’t? To take this into trương mục, we are able to maintain Eric’s content material technology CSS intact, utilizing that as a fall-back to our script, and eradicating it when the script runs efficiently.

That is achieved by retaining the unique CSS declarations for producing the href content material after which, when the script runs, we class-ify <html> as “famous.” We then add a rule to our print model sheet to disable the content material technology when the hyperlinks in query are descendants of html.famous:

html.famous a:hyperlink:after,
html.famous a:visited:after {
  content material: "";
}

So there you will have it, a pleasant, clear, printable doc with all hyperlinks and citations collected into footnotes. Use it, get pleasure from it, and enhance on it. For instance, you may add within the capability to disregard explicit hyperlinks classed as “ignore.” Get artistic and tell us what you give you.

You possibly can obtain the most recent compressed model of footnoteLinks from its homepage or obtain the working recordsdata for this text from this web site. All the JavaScript prototypes used on this article are contained in jsUtilities 2.1, which is obtainable as a compressed obtain from its homepage.

Leave a Comment