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
    Write Better JavaScript with Promises

    You've probably heard the talk around the water cooler about how promises are the future. All of the cool kids are using them, but you don't see what makes them so special. Can't you just use a callback? What's the big deal? In this article, we'll...

  • By
    Animated 3D Flipping Menu with CSS

    CSS animations aren't just for basic fades or sliding elements anymore -- CSS animations are capable of much more.  I've showed you how you can create an exploding logo (applied with JavaScript, but all animation is CSS), an animated Photo Stack, a sweet...

Incredible Demos

  • By
    Create a Simple Dojo Accordion

    Let's be honest:  even though we all giggle about how cheap of a thrill JavaScript accordions have become on the web, they remain an effective, useful widget.  Lots of content, small amount of space.  Dojo's Dijit library provides an incredibly simply method by which you can...

  • By
    Use Elements as Background Images with -moz-element

    We all know that each browser vendor takes the liberty of implementing their own CSS and JavaScript features, and I'm thankful for that. Mozilla and WebKit have come out with some interesting proprietary CSS properties, and since we all know that cementing standards...

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!