Treehouse

MooTools 1.2 OpenLinks Plugin

By on  

I often incorporate tools into my customers' websites that allow them to have some control over the content on their website. When doing so, I offer some tips to my clients to help them keep their website in good shape. One of the tips I tell my customer is "whenever you create links to PDFs, Excel XLS', Word DOCs, or JPG/GIF/PNG images, make the link open in a new window." Unfortunately, my customers don't always follow this guideline.

In an effort to correct their mistakes, I've created a MooTools class that analyzes links on the page and adds a target attribute when necessary.

The Usage

window.addEvent('domready', function() {
var olinks = new OpenLinks(['doc','pdf','xls','jpg','gif','png'],1,'_that_window','no-target');
});

The class takes four arguments:

  • file_extensions: an array of file extensions you would like to open in a new/specified window. Add file extensions without the '.' and lower-cased.
  • override_targets: boolean, representing whether you want an anchor's "target" attribute to be overidden
  • target: string, defaults to "_blank" if none provided
  • no_class: if you don't want a link's target attribute set, add your custom class to those links.

As you can see in the code example above, I want the following file extensions to open in a window named "_that_window": Word DOCs, PDFs, XLS files, JPGs, GIFs, and PNGs. Links with the class no-target are not modified, even if the file extension is a match.

The Moo JavaScript

var OpenLinks = new Class({
//initialization
initialize: function(file_extensions,override_targets,target,no_class) {

//analyze all anchors
$$('a').each(function(el) {

//check each href for case-insensitive file extensions
var str = el.get('href');
var ext = str.substring(str.lastIndexOf('.') + 1,str.length)
if(file_extensions.contains(ext.toLowerCase()) && ((override_targets || !el.get('target')) && !el.hasClass(no_class + '')))
{
el.setProperty('target',target ? target : '_blank');
}
});
}
});

The Flow

For every link in the document, I extract the file extension. If the link's file extension is in the array of marked file extensions...and the link's target can be overridden or the link doesn't have a target set...and the link doesn't have the specified class...the link is then modified. It's that simple!

Click here to view an example of the class in use.

Click here to download the class in an external .js file.

Note

I'd initially built the class to use more specific CSS selectors:

a[href$='.pdf'], a[href$='.jpg'], a[href$='.doc']//...

The problem with doing this is that the above method doesn't allow for case-insensitiveness. For example, "pdf" would match but "PDF" would not.

Update

MooTools dev digitarald caught wind of my class and coded the following JavaScript to make the class' code a bit shorter:

// a lovely fast case-insensitive regexp build from file extensions
var rex = new RegExp('\\.(?:' + file_extensions.join('|') + ')$', 'i');
 
// href und target sind native properties for links, no get() needed
// no_class is now a required parameter
target = target || '_blank';
 
$$('a[href]:not(.' + no_class + ')').each(function(el) {
  if ((force || !el.target) && rex.test(el.href)) el.target = target;
});

Thank you dig'!

ydkjs-5.png

Recent Features

  • Facebook Open Graph META Tags

    It's no secret that Facebook has become a major traffic driver for all types of websites.  Nowadays even large corporations steer consumers toward their Facebook pages instead of the corporate websites directly.  And of course there are Facebook "Like" and "Recommend" widgets on every website.  One...

  • Creating Scrolling Parallax Effects with CSS

    Introduction For quite a long time now websites with the so called "parallax" effect have been really popular. In case you have not heard of this effect, it basically includes different layers of images that are moving in different directions or with different speed. This leads to a...

Incredible Demos

  • Vibration API

    Many of the new APIs provided to us by browser vendors are more targeted toward the mobile user than the desktop user.  One of those simple APIs the Vibration API.  The Vibration API allows developers to direct the device, using JavaScript, to vibrate in...

  • The Simple Intro to SVG Animation

    This article serves as a first step toward mastering SVG element animation. Included within are links to key resources for diving deeper, so bookmark this page and refer back to it throughout your journey toward SVG mastery. An SVG element is a special type of DOM element...

Discussion

  1. Garrick

    Wouldn’t it be better to addEvent instead of adding a target attribute?

    Your method is just like adding the target attribute inline, which is not standards compliant.

    So you could do something like this instead:
    el.addEvent(‘click’, function(e){
    (new Event(e)).stop();
    //plugin your own code in the open function.
    window.open();
    });

  2. @Garrick: I did things this way because people don’t always click on links. Inserting a target attribute makes the browser handle these links as they would had they been properly targeted.

  3. This is one of those cases where I struggle with “well, it validates, because I’m assigning the invalid stuff via JS”. Target’s been deprecated for awhile… so I shy away from using it, simply because there must have been SOME reason it’s frowned upon..

  4. @Andrea: Thank you for sharing!

  5. I personally never open links in new windows, ever. Jakob Nielsen agrees, with the exception of rich internet apps that demand a full, new browser window (and which omit standard browser controls like the back button). Otherwise, opening links in new windows should be at the option of the user.

    That being said, I appreciate that we sometimes must compromise for a client and your solution certainly is clean and to the point.

    Which particulars of your code are specific to MooTools 1.2? I’m going to write a series of articles comparing differences to the MooTools codebase between v1.11 and 1.2, and am curious if you’re using any 1.2-specific functionality in this code.

    Here’s the first article I wrote, which contains a brief overview of the additions/changes in MooTools 1.2:

    http://www.thetruetribe.com/2008/06/whats-new-in-mootools-12.php

  6. @Jonah: One of my biggest web pet peeves is when a PDF, DOC, or XLS file is not opened in a new window. You end up being done with the document, close the program, and realize you just closed your browser and all the tabs you had open. That inspired me to create this class.

  7. I see your point– it’s natural to hit the “x” to close a document when you’re finished with it, and can accidentally close the page you were on.

    After reading up on Jakob Nielsen’s alert box, it appears he agrees with you as well:

    http://www.useit.com/alertbox/open_new_windows.html

    Here’s what Jakob has to say about it:

    “Because users frequently close document windows, the best guidelines for linking to non-Web documents are:

    1. Open non-Web documents in a new browser window.
    2. Warn users in advance that a new window will appear.
    3. Remove the browser chrome (such as the Back button) from the new window.
    4. Best of all, prevent the browser from opening the document in the first place. Instead offer users the choice to save the file on their harddisk or to open it in its native application…”

    I think this is best for the majority of users, and power users can just override the browser’s new window functionality.

    Incidentally, to override target=”” links opening in a new window in Firefox, you can tweak the browser.link.open_newwindow setting in about:config — setting it to 1 opens target=”” links in the current tab, setting it to 2 opens them in a new window and 3 opens in a new tab (default).

  8. […] long time back I coded a MooTools class called OpenLinks. The class is quite useful but the code…sucks. I've gotten much better with MooTools over the […]

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