views:

69

answers:

1

Even though I've been using mootools for a while now, I haven't really gotten into playing with the natives yet. Currently I'm trying to extend events by adding a custom addEvent method beside the original. I did that using the following code(copied from mootools core)

Native.implement([Element, Window, Document], {
    addMyEvent:function(){/* code here */}
}

Now the problem is that I can't seem to figure out, how to properly overwrite the existing fireEvent method in a way that I can still call the orignal method after executing my own logic.

I could probably get the desired results with some ugly hacks but I'd prefer learning the elegant way :)


Update: Tried a couple of ugly hacks. None of them worked. Either I don't understand closures or I'm tweaking the wrong place. I tried saving Element.fireEvent to a temporary variable(with and without using closures), which I would then call from the overwritten fireEvent function(overwritten using Native.implement - the same as above). The result is an endless loop with fireEvent calling itself over and over again.

Update 2: I followed the execution using firebug and it lead me to Native.genericize, which seems to act as a kind of proxy for the methods of native classes. So instead of referencing the actual fireEvent method, I referenced the proxy and that caused the infinite loop. Google didn't find any useful documentation about this and I'm a little wary about poking around under the hood when I don't completely understand how it works, so any help is much appreciated.


Update 3 - Original problem solved: As I replied to Dimitar's comment below, I managed to solve the original problem by myself. I was trying to make a method for adding events that destroy themselves after a certain amount of executions. Although the original problem is solved, my question about extending natives remain.

Here's the finished code:

Native.implement([Element, Window, Document], {
addVolatileEvent:function(type,fn,counter,internal){
    if(!counter)
        counter=1;
    var volatileFn=function(){
        fn.run(arguments);
        counter-=1;
        if(counter<1)
        {
            this.removeEvent(type,volatileFn);
        }
    }
    this.addEvent(type,volatileFn,internal);
}
});

is the name right? That's the best I could come up with my limited vocabulary.

+1  A: 
document.id("clicker").addEvents({
    "boobies": function() {
        console.info("nipple police");
        this.store("boobies", (this.retrieve("boobies")) ? this.retrieve("boobies") + 1 : 1);
        if (this.retrieve("boobies") == 5)
            this.removeEvents("boobies");
    },
    "click": function() {
        // original function can callback boobies "even"
        this.fireEvent("boobies");
        // do usual stuff.
    }
});

adding a simple event handler that counts the number of iterations it has gone through and then self-destroys.

think of events as simple callbacks under a particular key, some of which are bound to particular events that get fired up.

using element storage is always advisable if possible - it allows you to share data on the same element between different scopes w/o complex punctures or global variables.

Natives should not be modded like so, just do:

Element.implement({
    newMethod: function() {
        // this being the element
        return this;
    }
});

document.id("clicker").newMethod();

unless, of course, you need to define something that applies to window or document as well.

Dimitar Christoff
Thanks. You might want to check out the script I added to the question before. It's also available here: http://jsfiddle.net/ZVbWPMy method lets me use `addVolatileEvent` practically anywhere that supports the regular `addEvent` and it doesn't use element storage.
Pichan
this is over-engineered: check http://jsfiddle.net/ZVbWP/1/
Dimitar Christoff
By that definition many mootools convenience functions would also have to be called overengineered, don't you think? What I've done here is purely a convenience method for my own use to avoid needing to code the counters myself all the time(which should decrease the possible nesting grounds for bugs). Also note that my method doesn't rely on element storage and it's available also to Events class, not just element events.I'll gladly take all the crique(constructive please :) you can come up with, but I really can't see how this is overengineered.
Pichan
Using element storage is not a bad thing but quite the opposite, it's beneficial. in this instance, if you need to code a reset that reverts the counter back from a 3-rd link somewhere, you'd struggle to puncture the event scope and reset it so you'd probably have to remove and re-add the event. using element storage, eg `this.retrieve("clicked")` within the scope can be reset as `selector.store("clicked, 5)` from the `outside`. As for what's over-engineered or not, I won't comment _further_ - you need to understand and appreciate the need to _scale_ for each project before you can judge this.
Dimitar Christoff
Don't let the counter confuse you. When I need self-destructing events, I mostly need them to run only once. The counter is just an extra for the rare occasions where I might need an event run more than once.These 2 approaches don't rule each other out. If a modifiable counter is what I need, I could always do it your way, but since I suspect I'm not going to need to modify these events after they're set, I think I'm fine with my way :)
Pichan
Oh, and it seems I had missed your edit about not modding natives. That `Native.implement()` is actually a remnant from when I couldn't modify `fireEvent` properly and just then tried everything to make it work.Although `Native.implement` doesn't do anything else but loop through the first argument executing implement on every element of the array and doesn't have any side effects(code here: http://jsfiddle.net/sM3p9), I think you're right and I probably should stay clear of it.
Pichan
for run-once events, you can also do this within the event callback when you're done: `element.removeEvents(type);` downside to applying it on window and document as well is added overhead plus the future incompatibility that comes with mootools 1.3 and the move away from natives as a construct.
Dimitar Christoff
I want to avoid having to manually remove events once they've run. There's a small overhead to `addVolatileEvent` but it doesn't really matter. Doesn't `element.removeEvents` remove all events of the given type? Thanks for pointing out the incompatibility with 1.3. I don't have any need to include the method in document or window. I just made it available everywhere regular events are for now. It's going to change for sure.
Pichan
yeah it does remove the whole 'type' key which may or may not be an issue for you. using a named function to bind the event to makes it easy to remove in specifics so what you do is fine, really. only things i'd change is add ability to easily bind the callback function to the trigger element by default or to whatever class/element scope has been assigned (although you can bind the anon function at the addEvent stage anyway by adding `.bind(scope)`. http://www.jsfiddle.net/dimitar/bw2rm/
Dimitar Christoff
Looks good, thanks for the advice :)
Pichan