Treehouse

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.

ydkjs-5.png

Recent Features

  • Chris Coyier’s Favorite CodePen Demos

    David asked me if I'd be up for a guest post picking out some of my favorite Pens from CodePen. A daunting task! There are so many! I managed to pick a few though that have blown me away over the past few months. If you...

  • CSS vs. JS Animation: Which is Faster?

    How is it possible that JavaScript-based animation has secretly always been as fast — or faster — than CSS transitions? And, how is it possible that Adobe and Google consistently release media-rich mobile sites that rival the performance of native apps? This article serves as a point-by-point...

Incredible Demos

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!

  14. [...] lägga till händelser till att lägga till händelser i MooTools [...]

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