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
    5 Awesome New Mozilla Technologies You’ve Never Heard Of

    My trip to Mozilla Summit 2013 was incredible.  I've spent so much time focusing on my project that I had lost sight of all of the great work Mozillians were putting out.  MozSummit provided the perfect reminder of how brilliant my colleagues are and how much...

  • By
    Conquering Impostor Syndrome

    Two years ago I documented my struggles with Imposter Syndrome and the response was immense.  I received messages of support and commiseration from new web developers, veteran engineers, and even persons of all experience levels in other professions.  I've even caught myself reading the post...

Incredible Demos

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!