MooTools OpenLinks Class – Updated

By  on  

A 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 past years so I thought I'd go back and update the class to be better, faster, etc.

The Original MooTools Class

/* classes */
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');
				el.setStyle('color','#f00');
			}
		});
	}
});

Gross. Everything is an argument and the no_class argument is pointless since you can simply disqualify items in the elements option selector string.

The New MooTools JavaScript

/* class */
var OpenLinks = new Class({
	
	Implements: [Options],
	
	options: {
		elements: 'a',
		extensions: [],
		target: '_blank',
		overrideTarget: true
	},
	
	initialize: function(options) {
		this.setOptions(options);
		$$(this.options.elements).each(this.assign,this);
	},
	
	assign: function(el) {
		var href = 	el.get('href'), ext = href.substring(href.lastIndexOf('.') + 1,href.length).toLowerCase();
		if(this.options.extensions.contains(ext) && (this.options.overrideTarget || !el.get('target'))) {
			el.set('target',this.options.target);
		}
	}
	
});

Instead of making everything arguments I moved each argument into the options object. I also removed the no_class option/parameter.

The MooTools Usage

/* usage */
window.addEvent('load',function() {
	var openers = new OpenLinks({
		extensions: ['pdf','xls','doc','jpg'],
		elements: '#content a'
	});
});

Using OpenLinks is as easy as it should be!

It feels good to clean up code after a long time. I recommend you do so when you can too!

Recent Features

  • By
    Page Visibility API

    One event that's always been lacking within the document is a signal for when the user is looking at a given tab, or another tab. When does the user switch off our site to look at something else? When do they come back?

  • By
    Being a Dev Dad

    I get asked loads of questions every day but I'm always surprised that they're rarely questions about code or even tech -- many of the questions I get are more about non-dev stuff like what my office is like, what software I use, and oftentimes...

Incredible Demos

Discussion

  1. quite cool …. but how about in jQuery side ?

  2. Very nice. Could be extended further to take the styles of the affected links as an option. This way people would be able to style their links during declration, instead of adjusting the class, el.setStyles(this.options.styles), or similar.

    Mootools FTW!

  3. @Colin Gillies: My bad — the link color wasn’t meant to be a part of this — it was only for the example. Removed.

  4. Anton

    That is what I hate. AFAIK, target is no longer part of XHTML. Besides, *user* should decide, whether to open a link in a new window or not.

  5. @Anton: I disagree. Many users click a link to open the PDF and close their browser to “close” the PDF. Then what? They’ve just closed their entire browser and “lost their spot”, so to speak. I contend that any developer should be able to decide if something opens in a new window.

  6. Anton

    @David Walsh: tell that to W3C. Users should be aware of the applications they use, including browser. And modern browsers know how to save last opened pages, so reopening the browser will not be a problem. Besides, a PDF will not open inside a browser, if there is no plugin installed for such behavior.

  7. @Anton: The W3C and validating services can say what they want. The “target” attribute works everywhere and since PDFs open in another program traditionally (Acrobat), opening a new window shouldn’t be anything out of the ordinary.

    Also note that I doubt persons who accidentally close their window know how to recover tabs.

    Use the “grandma” rule — if she doesn’t know, many others wont know.

  8. Anton

    @David Walsh: If my grandma doesn’t know how to switch gears on a manual gearbox, I don’t buy her a car with an automatic gearbox, I make her learn to drive.

    Also:
    – Firefox recovers tabs automatically if there wasn’t an error, same for most other browsers;
    – PDFs, even without target, open as a separate application (after downloading), if there is no PDF plugin in the browser.

  9. @Anton: How do you propose teach thousands of “grandmas” out there how to do some of this stuff? If you own a business, you still want my grandma’s money, don’t you? Most “grandmas” don’t know FireFox — most “grandmas” click the blue “E” icon.

  10. Listen2Me

    I’m with you on this one David; with the W3C removing target from the XHTML standard it has left us having to use window.open() instead. I’d love to see an implementation of your script that parses the string inside the HREF attribute for “http://” and opens these links in a new window as well.

  11. @Listen2Me: Seems easy enough, although in my experience, window.open() is more at risk of being blocked by popup blockers.

  12. Just my 2p, but I agree with David. As much as I like to adhere to W3C, when it comes to opening non-HTML files into the browser I always go for a new window. I have lost count how many times I have watched a client open a PDF / DOC in their browser and then closed the browser thinking it will return them to the site.

    We can’t teach everyone how to do it ‘properly’ without leaving long instructions next to each link. Also, most of the time the application or document isn’t W3C / accesibility friendly anyway.

  13. I’d put the elements in an argument of the initialize function. When I create classes I try to think about what is and isn’t an option. In this case, the links aren’t really an option, they are the whole point of the class.

    And for me, writing this.elements feels better than this.options.elements.

    As for the new window discussion:

    I’ve been doing software training/consulting for several years now for web-based software and have seen countless people “lose their place” when they close the browser thinking they’re just closing the PDF or whatever as David points out.

    However, I’ve also seen just as many people throw their hands up in frustration because the site or application popped up a new window and they “lost their document” or whatever. It’s not lost, it’s just behind the one you’re looking at, after all, it’s called windows for a reason.

    The decision has to be well thought out to pop open a new window or not based on the audience and context. I’m a fan of _blank when it’s appropriate. While I respect the w3c, I don’t understand the cultish clinging to ridiculous standards by the (mostly) basement developers. These aren’t medical documents anymore w3c, they’re applications.

  14. Also … new OpenLinks('a.open') is way better than new OpenLinks({ elements: 'a.open'})

  15. I think the best choice is to let users decide when to open a web page in a new tab/window, but force external documents to open new tabs.

  16. According to the W3C, they realized they made a mistake in deprecating the target attribute. They put it back in in HTML 5.

    http://www.w3.org/TR/html5-diff/

  17. @FoO Iskandar: Requesting the same thing here.

  18. EmEhRKay

    While I agree with David about the usefulness of target, my only beef is that this doesnt create valid html. Instead of doing el.set(‘target’…), one could attach a click event (yeah, the standard work-around for the removal of target) that would mimic target’s behavior.

  19. @EmEhRKay: So window.open? It’s a preference thing I guess but I prefer target-blank as it isn’t as often blocked by popup blockers.

  20. Evan

    I totally hate the idea of “external” links opening in a new window but I prefer for pdf files to open in a new window.

    With window.open you can’t really maximize a window or open it as a tab. The best you can do is get the screen size and open the new window to that dimension but it’s still not maximized. Setting the target to _blank just seems to work better.

    If you care about the appearance of your html validating you can set up the script to add the target attribute.

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