O'Reilly

Adding Events to Adding Events in MooTools

By on  

Note: This post has been updated.

One of my huge web peeves is when an element has click events attached to it but the element doesn't sport the "pointer" cursor. I mean how the hell is the user supposed to know they can/should click on something? It's insane. I've called Chris Coyier out on it, fellow developers out on it, and hell -- I'd call my mother out on it if I had to.

I set out to find a method to automatically give the pointer cursor to elements that get a "click" event attached to them. Essentially, I wanted to add an event to adding an event. Fortunately MooTools makes this possible.

The MooTools JavaScript

/* update cursor on add/remove click event */
Element.Events.click = { 
	base:'click',
	onAdd: function() {
		this.setStyle('cursor','pointer');
	},
	onRemove: function() {
		this.setStyle('cursor','');
	}
};
/* usage */
window.addEvent('domready',function() {
	$('click-me').addEvent('click',function() {
		/* execute whatever you want, but the pointer cursor is added */
	});
	$('click-me').removeEvents('click'); // cursor gone
});

I create a custom click event, based on the click event, and add the "pointer" cursor when the click event is added and then I remove that cursor when the click event is removed. So simple!

Now if only I could get browser vendors to implement this...Oh well -- one step at a time!

The Updated MooTools JavaScript

/* update cursor on add/remove click event */
Element.Events.click = { 
	base:'click',
	onAdd: function() {
		if(this.setStyle) {
			this.store('original-cursor',this.getStyle('cursor'));
			this.setStyle('cursor','pointer');
		}
	},
	onRemove: function() {
		if(this.setStyle) {
			this.setStyle('cursor',this.retrieve('original-cursor'));
		}
	}
};

This updated version takes into account the element's original cursor.

Track.js Error Reporting

Upcoming Events

Recent Features

  • 7 Essential JavaScript Functions

    I remember the early days of JavaScript where you needed a simple function for just about everything because the browser vendors implemented features differently, and not just edge features, basic features, like addEventListener and attachEvent.  Times have changed but there are still a few functions each developer should...

  • 9 Mind-Blowing WebGL Demos

    As much as developers now loathe Flash, we're still playing a bit of catch up to natively duplicate the animation capabilities that Adobe's old technology provided us.  Of course we have canvas, an awesome technology, one which I highlighted 9 mind-blowing demos.  Another technology available...

Incredible Demos

  • Create a Simple News Scroller Using Dojo

    My journey into Dojo JavaScript has been exciting and I'm continuing to learn more as I port MooTools scripts to Dojo. My latest experiment is porting a simple new scroller from MooTools to Dojo. The code is very similar! The HTML The news items...

  • Google Font API

    Google recently debuted a new web service called the Font API.  Google's Font API provides developers a means by which they may quickly and painlessly add custom fonts to their website.  Let's take a quick look at the ways by which the Google Font...

Discussion

  1. You’re drunk with power!

  2. I totally agree with you. It really annoys me when a clickable element doesn’t have a pointer cursor. this might be a silly question, but any idea whether this is possible in jQuery?

  3. @Geoff: I’ll investigate that.

  4. DJ

    Looks like endrew’s pointed you to it and jQ’s got the right stuff. How about a jQ version?

  5. Fantastic! When I tried this, it worked perfectly except that I have some code that adds a ‘click’ event handler to the document when a popup opens so that it closes if the user clicks outside the popup and document.setStyle doesn’t exist – so I added if (this.setStyle) {} around the code to make it work for me.

  6. Иван

    (I like the idea very much. It’s just some thought I have on it.)

    I strongly believe that the design should appeal to the user for interaction — if something can be interacted (click, drag, resize — you name it) with, it should have the proper cursor set, regardless of whether the interaction came from progressive enhancement or not.

    In the case of the front end getting the job right and the user still not being able to grasp where is the clickable area, the user is:

    a) extremely dumb
    b) born in the early 19th century and is currently worshiping the big (even bigger if it is a CRT) black box

    However, one can never be sure (that the front end did job right) so this might come in handy.

  7. Patrick

    Hey David, really liked that small example for the expandability in mootools.

    Using a similar bunch of code in a commercial project led to 3 hours of JS-debugging here however – let me explain:

    I extended the click-Event in the same way you did, but added an additional check for the tagname of the element (don’t need to add a click-cursor, if the element in question is an <a>-element (when using makeResizable on such an element, you’ll lose the resize-cursor if you don’t fix this).

    Everything went fine in Firefox and Webkit, but in IE8 it all fell apart. I’m still trying to find out, what combination of code let to this error, but long story short:

    IE8 halted JS-execution because of an error in the mootools-core.js – this line of code:

    getComputedStyle: function(property){
        if (this.currentStyle) return this.currentStyle[property.camelCase()];
        var computed = this.getDocument().defaultView.getComputedStyle(this, null);
        return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null;
    }, ");
    

    As we all know, IE has some problems with getProperty and setProperty on elements that weren’t in the original DOM the server sent to the browser. Now as the bad boy that I am, I created my own mootools class for notification boxes. They can be dragged, resized, closed or they can be tooltops, little popups showing where something went wrong on the website with a litte arrowhead, you name it. Beautiful thing, just one class I could do all this stuff with.

    This class is created before the DOM is loaded, but not instantiated (important difference) – two instances are then created when the domReady-event is fired. But somewhere between creating the instances and adding the event to the click-event, IE8 seems to crumble. If I’m moving your part of the code to the domReady-event, nothing changes, the only “fix”, was using an IE-browserdetection and hiding this particular piece of code from IE..

    It’s as if IE is already firing the onAdd-event even though the DOM hasn’t been loaded yet (read: IE seems to evaluate the initialize()-method of my class before it’s even instantiated).

    So nothing left to say but “Beware of IE!” – if you’d like to see the code that brought IE to its knees (even though it’s all working fine in every other browser), feel free to contact me!

  8. @Patrick: I’ve the error that you explained on Internet Explorer 8 but I don’t understand how I can solve it.

  9. Patrick

    Alright here’s some things I noticed, that every MooTools developer should keep in mind (these things were connected to my issues above..):

    Don’t use names for input fields that might’ve been reserved by mootools already – e.g. send!
    Explanation: Mootools adds a method send() to elements (used with Request) – lots of people like to give their <input type=”submit” /> an additional name, so that they can check for a submitted form in php (if (!empty($_POST["send"]))...) – now “send” is already taken by mootools, giving this input another property named “send” would require an overwrite of an element property, which IE (no matter which version) will respond to with an “The Object doesn’t support…” error – should be fixed in MooTools 2.0 but for now, simply avoid names or properties with “reserved” names (e.g. use “sent” instead).
    Here’s what I came up with for the “adding link-cursor for clickable elements”-trick (works without errors in any IE so far):

    /* update cursor on add/remove click event */
    Element.Events.click = {
    
    Element.Events.click = {
    base:'click',
    onAdd: function() {
        if(this.getStyle && this.get("tag") != "a" && !this.match("input[type=text]") && !this.match("input[type=password]")) {
            this.store('original-cursor',this.getStyle('cursor'));
            this.setStyle('cursor','pointer');
        }
    },
    onRemove: function() {
        if(this.setStyle && this.get("tag") != "a" && !this.match("input[type=text]") && !this.match("input[type=password]")) {
            this.setStyle('cursor',this.retrieve('original-cursor'));
        }
    }
    
    };
    

    It’s still rough (the selector could be refined that makes sure that this style-switching only occurs on elements which aren’t links already or aren’t neither an input-element containing text or an input-element containing a password value (which should show a textinput cursor).

    Somehow (don’t ask me why), this.setStyle (which results in setComputedStyle in IE), won’t work in IE correctly when adding Events to Events, getStyle however worked…

  10. The error happened when I replace the content of a div that contains a DatePicker of ClientCide via an AJAX request. The ID and the “name” of the input text with DatePicker is “end_date”.

  11. Patrick

    What’s the exact error message? I hope you’re using IE8 to debug this error, or maybe even JSCompanion for IE.

  12. This is a great little script but it completely fails you if you use Event Delegation.

    Your adding cursor pointer to, for example an entire list or the parent UL, instead of the list elements LI.

    I have one app that uses a click event on the body of the document and delegates the events depending on what div you clicked. So the entire document now has a pointer cursor.

    So be warned if you use Delegation techniques.

  13. Tim John

    Nice one David. I totally agree that the finger cursor is there to indicate clickability, so I’m using your code in my library from now on. Thanks!

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

Recently on David Walsh Blog

  • Free Download: Font Bundle Featuring 17 Incredible Typefaces

    The only thing we love more than a good font, is a good free font. So we’ve combed the Web for some of our favorite free fonts, and gathered them here in a single download. You’ll find a variety of useful typefaces, from highly geometric designs...

  • OâReilly Velocity Conference â Amsterdam

    My favorite front-end conference has always been O'Reilly's Velocity Conference because the conference series has focused on one of the most undervalued parts of client side coding:  speed.  So often we're so excited that our JavaScript works that we forget that speed, efficiency, and performance are just as important. The next Velocity...

  • CanIUse Command Line

    Every front-end developer should be well acquainted with CanIUse, the website that lets you view browser support for browser features.  When people criticize my blog posts for not detailing browser support for features within the post, I tell them to check CanIUse:  always up to date, unlike...

  • Generating Alternative Stylesheets for Browsers Without @media

    If your CSS code is built with a mobile-first approach, it probably contains all the rules that make up the "desktop" view inside @media statements. That's great, but browsers that don't support media queries (IE 8 and below) will simply ignore them, ending up getting the...

  • Serve a Directory with PHP

    Many developers have a giggle at PHP, even looking down at the language, but let's be honest:  most of our blogs are powered by it (WordPress) and it's a great language to dabble around with.  I cut my teeth on PHP, though I prefer to avoid PHP these days. But...