Introducing MooTools LinkAlert

By  on  

One of my favorite Firefox plugins is called LinkAlert. LinkAlert shows the user an icon when they hover over a special link, like a link to a Microsoft Word DOC or a PDF file. I love that warning because I hate the surprise of opening a PDF file. The problem with LinkAlert in its current state is that it's only available with Firefox...until now. Armed with my favorite JavaScript library, MooTools, I've duplicated the functionality of LinkAlert.

The MooTools JavaScript Class

var LinkAlert = new Class({

	//implements
	Implements: [Options,Events],

	//options
	options: {
		container: document.body,
		extensions: {},
		offsets: { x:6, y:-15 },
		preloadImages: true,
		protocols: {},
		sticky: false,
		onShow: function(el,image) {
			this.image.setStyle('display','');
		},
		onHide: function(el,image) {
			this.image.setStyle('display','none');
		}
	},
	
	//initialization
	initialize: function(options) {
		//set options
		this.setOptions(options);
		this.extensions = new Hash(this.options.extensions);
		this.protocols = new Hash(this.options.protocols);
		this.image = new Element('img',{
			src: '',
			styles: {
				position: 'absolute',
				top: -200,
				left: -200,
				visibility: 'hidden'
			}
		}).inject(document.id(document.body));
		//preload images, if necessary
		if(this.options.preloadImages) { this.preloadImages(); }
		//add the listeners
		this.addListeners(this.extensions,'$=','extensions');
		this.addListeners(this.protocols,'^=','protocols');
	},
	
	//give direction to links
	addListeners: function(items,sep,type) {
		//for every item
		items.each(function(image,extension,type) {
			//for every link of that type
			$$('a[href' + sep + '\'' + extension + '\']').each(function(el) {
				//if the same protocol, don't bother showing
				if(type == 'protocol' && window.location.protocol == extension + ':') { return; }
				//add the show/hide events
				el.addEvents({
					mouseenter: function(e) {
						//position the image and give it the proper SRC
						this.reposition(e).set('src',image);
						//fire the event
						this.fireEvent('show',[el,image]);
					}.bind(this),
					mouseleave: function(e) {
						//fire the event
						this.fireEvent('hide',[el,image]);
					}.bind(this)
				});
				//sticky?
				if(this.options.sticky) {
					el.addEvent('mousemove',function(e) {
						this.reposition(e);
					}.bind(this));
				}
			},this);
		},this);
	},
	
	//repositions
	reposition: function(e) {
		return this.image.setStyles({
			left: e.page.x + this.options.offsets.x,
			top: e.page.y + this.options.offsets.y
		});
	},
	
	//preloads necessary images
	preloadImages: function() {
		var images = [this.protocols.getValues(),this.extensions.getValues()].flatten();
		new Asset.images(images);
	}
});

Options for LinkAlert include:

  • container: (defaults to document.body) The container to search for links within.
  • extensions: (defaults to {}) An object container file extensions and images to look for.
  • offsets: (defaults to { x:6, y:-15 }) The x and y offset from the mouse the icon should display.
  • preloadImages: (defaults to false) Whether or not to preload all file extension and protocol icons.
  • protocols: (defaults to {}) An object container protocols and images to look for.
  • sticky: (defaults to false) Defines whether the icon should follow the mouse while the mouse is hovered over a link.

Events for LinkAlert include:

  • Show: Fires when an icon shows.
  • Hide: Fires when an icon hides.

Sample Usage

/* do it */
window.addEvent('domready', function() {
	var graphicsDir = 'link-alert/';
	var context = new LinkAlert({
		extensions: {
			doc: graphicsDir + 'word.png',
			js: graphicsDir + 'js.png',
			pdf: graphicsDir + 'pdf.png',
			txt: graphicsDir + 'text.gif',
			xls: graphicsDir + 'xls.png',
			jpg: graphicsDir + 'jpg.png'
		},
		protocols: {
			ftp: graphicsDir + 'ftp.png',
			https: graphicsDir + 'secure.png',
			'javascript:': graphicsDir + 'js.png'
		},
		preloadImages: true,
		sticky: true,
		onShow: function(el,image) {
			this.image.fade('in');
		},
		onHide: function(el,image) {
			this.image.fade('out');
		}
	});
});

I use a few of the options and custom show and hide functionality.

I don't know if this plugin has practical usage for all users but I'll definitely be using it for sites that are in-development. Have any any other uses for this? Share them!

Recent Features

  • By
    Responsive Images: The Ultimate Guide

    Chances are that any Web designers using our Ghostlab browser testing app, which allows seamless testing across all devices simultaneously, will have worked with responsive design in some shape or form. And as today's websites and devices become ever more varied, a plethora of responsive images...

  • By
    5 More HTML5 APIs You Didn’t Know Existed

    The HTML5 revolution has provided us some awesome JavaScript and HTML APIs.  Some are APIs we knew we've needed for years, others are cutting edge mobile and desktop helpers.  Regardless of API strength or purpose, anything to help us better do our job is a...

Incredible Demos

  • By
    pointer Media Query

    As more devices emerge and differences in device interaction are implemented, the more important good CSS code will become.  In order to write good CSS, we need some indicator about device capabilities.  We've used CSS media queries thus far, with checks for max-width and pixel ratios.

  • By
    MooTools ContextMenu Plugin

    ContextMenu is a highly customizable, compact context menu script written with CSS, XHTML, and the MooTools JavaScript framework. ContextMenu allows you to offer stylish, functional context menus on your website. The XHTML Menu Use a list of menu items with one link per item. The...

Discussion

  1. ali

    jQuery please!!!

  2. Mr.X.

    I find css selectors better. Don’t take me wrong this is great, but if you have a lot of script on your site, this would not be something I would recommend. Using just css is way smaller and has the same effect without fancy animation. For anyone who does not know about this.

    Nice script.

    Cheers!

  3. @Mr.X.: I’d usually agree but having icons all over place makes the page look like a circus.

  4. Mr.X.

    @David Walsh maybe so but it is easily fixed.

    You can do it like this

    print("a[href $= '.pdf']{padding-left:20px;}");
    
    print("a[href $= '.pdf']:hover{background: transparent url(../style/icons/pdf.png) no-repeat scroll left top;}");
    
  5. Marc

    Well, I haven’t set it up, but you could use it as user javascript in opera. Then it would pop up for all links in all website. This could be an alternative use I think.

  6. David, thanks a lot for that.
    Another of many useful tips, if I may call your hard work like that! =)

    Thanks!

  7. Wow, a nice piece of work!
    Like Marc said as userJS it’s a good alternative for the Firefox plugin for Opera users.

    But i must admit that for a single website the CSS solution of Mr.X. is more elegant.

    Anyway THX for this useful class.

  8. Wow, this is really nice. I think tweaking it to include the file path and putting in a little box to the lower right of the mouse would be perfect for my needs.

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