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.

Recent Features

  • By
    Introducing MooTools Templated

    One major problem with creating UI components with the MooTools JavaScript framework is that there isn't a great way of allowing customization of template and ease of node creation. As of today, there are two ways of creating: new Element Madness The first way to create UI-driven...

  • By
    Facebook Open Graph META Tags

    It's no secret that Facebook has become a major traffic driver for all types of websites.  Nowadays even large corporations steer consumers toward their Facebook pages instead of the corporate websites directly.  And of course there are Facebook "Like" and "Recommend" widgets on every website.  One...

Incredible Demos

  • By
    Fullscreen API

    As we move toward more true web applications, our JavaScript APIs are doing their best to keep up.  One very simple but useful new JavaScript API is the Fullscreen API.  The Fullscreen API provides a programmatic way to request fullscreen display from the user, and exit...

  • By
    Introducing MooTools Templated

    One major problem with creating UI components with the MooTools JavaScript framework is that there isn't a great way of allowing customization of template and ease of node creation. As of today, there are two ways of creating: new Element Madness The first way to create UI-driven...

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!