slightlyoff / Promises

DOM Promises IDL/polyfill
Apache License 2.0
154 stars 28 forks source link

handleEvent support #48

Open termi opened 11 years ago

termi commented 11 years ago

If Future will pass event object as a first parameter to callback

EventTarget.prototype.once = function(eventType, options) {
   var self = this;
   return new Future(function (resolver) {
     self.on(eventType, options, function(event)) {
       resolver.accept(event);
     });
   });
 };

I suggest this:

EventTarget with DOM Future someway, somehow, should support handleEvent. Right now I can write:

var model = {
    handleEvent: function(e) {
        var handlerName = "$" + e.type;

        if( handlerName in this ) {
            return this[handlerName](e);
        }
    }

    , $click: function(e) {
        console.log(e.type)
    }

    , $mouseover: function(e) {
        console.log(e.type)
    }

    , init: function(node) {
        for( var eventName in this ) {
            if( eventName[0] == "$" ) {
                node.addEventListener(eventName.substr(1), this);
            }
        }
    }
}

model.init(document.find(".some_node"));

or

var xhrController = {
    handleEvent: function(e) {
        switch(e.type) {
            case "load":
                //do something
            break;
            case "abort":
                //do something
            break;
            default:
                console.log(e.type, e);
        }
    }

    , init: function(xhr, url) {
        this.xhr = xhr;
        this.url = url;
        ["load", "error", "abort", "loadend", "loadstart", "progress", "timeout"].forEach(function(name) {
            xhr.addEventListener(name, this);
        }, this);
    }

    , send: function(data) {
        xhr.open("POST", this.url);
        xhr.send(data);
    }
}

xhrController.init(new XMLHttpRequest({anon: true}), "//example.com/");

or even

var rootClickEvents = [];
document.addEventListener("click", rootClickEvents);

//somewhere in script

rootClickEvents.handleEvent = function(e) {
    this.forEach(function(handler) {
        handler.call(e.currentTarget, e);
    })
}

//...
rootClickEvents.push(function(e) {
    console.log(e.type, e);
});

In DOMFuture proposal it doesn't even mention the handleEvent.

I think event object should contains a Future/Promise state information.

annevk commented 11 years ago

You can use bind for this.

termi commented 11 years ago

You propose new DOM events API, but you break the existing features. And no, I can't using .bind for this. Take a look on this example (real application is more difficult):

var eventObject = {
    handleEventAllEvents: function(e) {
        console.log(e, 'all events');

        if( e.type == 'click' ) {
            // For some point we need handle First keyboard event in another handler
            this.handleEvent = this.handlerEventsOnlyKeyboadrEvent;
        }

    }

    , handlerEventsOnlyKeyboadrEvent: function(e) {
        // handle First keyboard event
        if( "keydown|keyup|input".contains(e.type) ) {
            console.log(e, 'first keyboard event')
            this.handleEvent = this.handleEventAllEvents;
        }
    }
};
eventObject.handleEvent = eventObject.handleEventAllEvents;

document.addEventListener("click", eventObject);
document.addEventListener("keydown", eventObject);

without handleEvent support I need always add and remove event listeners and binding all methods that I want using as event handler.

var eventObject = {
    handleAllEvents: function(e) {
        console.log(e, 'all events');

        if( e.type == 'click' ) {
            // For some point we need handle First keyboard event in another handler
            e.currentTarget.off("click", {handler: this.handleAllEvents});
            e.currentTarget.on("keydown", {handler: this.handlerOnlyKeyboadrEvent});
        }

    }

    , handlerOnlyKeyboadrEvent: function(e) {
        // handle First keyboard event
        if( "keydown|keyup|input".contains(e.type) ) {
            console.log(e, 'first keyboard event')
            e.currentTarget.off("keydown", {handler: this.handlerOnlyKeyboadrEvent});
            e.currentTarget.on("click", {handler: this.handleAllEvents});
        }
    }
};

eventObject.handleAllEvents = eventObject.handleAllEvents.bind(eventObject);
eventObject.handlerOnlyKeyboadrEvent = eventObject.handlerOnlyKeyboadrEvent.bind(eventObject);

document.on("click", {handler: eventObject.handleAllEvents});

I find this very complicated and unusable. EventTarget.prototype.[on/off] in this example is just a pseudo code.

Another example of using handleEvent from prototype Assume I write a class with handleEvent and created some amount of class instances. With handleEvent support I can pause all event handling by calling simple method ('stopEvents' for example). This will prevent all instances of this class from event handling. Without handleEvent support it's absolutely impossible (I am not considering the case of saving references to all created objects).

class eventTargetComponent {

    handleEvent(e) {
        // handle this
    }

    public static stopEvents() {
        this.prototype.__handleEvent = this.prototype.handleEvent;
        this.prototype.handleEvent = null;
    }
}

for( let i = 0 ; i < 100 ; i++ ) {
    document.addEventListener('application_event', new eventTargetComponent );
}
// preventing event handling
eventTargetComponent.stopEvents();

This is just a proof of concept, do not pay attention to the code.