-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proxy.on #127
Comments
Let me see if I can get discussion going again on this topic, as I want to implement it in relation to d3.js. Briefly what happens in d3.js is you create a "selection", with something like d3.selectAll("svg"), and this returns a d3 object that is in effect supposed to be a d3 representative for the svg nodes in the dom. I am envisioning in my incorporation of d3 into wire that these selections would become wire components, and I would want to be able to have an on facet on them. That would translate to an on method that those d3 selection objects have, that functions similarly but slightly differently to the corresponding on handler placed on the dom node itself. Namely (https://github.com/mbostock/d3/wiki/Selections#wiki-on) it takes an event type with the usual allowances for css selectors, and a handler to be called. A couple of things it does differently however:
A bit longwinded discussion of how d3 works, but I wanted to have it down somewhere. I'll start a new comment with questions/suggestions. |
So I think one first important question to answer is: Should this only work with dom events, but allow other components to "act" as dom elements if they are supposed to be managing one or more dom elements (backbone views, d3 selections etc). This would restrict the "event selectors" to the standard dom event and css selectors. So how would the API look like? I think expecting the signature of proxy.on to be proxy.on(eventSelector, handler) would be the most reasonable, unless we want a third optional parameter for what "this" should be set to when the handler is called. For event selectors I think either "eventName cssSelectors" or "eventName:cssSelectors" both seem reasonable forms. Just thinking out loud to get the discussion going. So technically what would need to change? The way I envision it, I think, is that the "wire/on" facet would:
Then the base plugin would essentially have an implementation that says "you can't do this", at least if we want to restrict to only dom-related events. And dom-related plugins would need to implement an "on" method in their proxies, starting with wire's dom object proxy, then backbone views, d3 etc. Is that roughly what you had in mind? |
Hey @skiadas, sorry I've been kinda buried this week. Let me get my head back into this, and I'll respond soon. I did some preliminary work a while back to lay the groundwork for this, so I'll take a look at that to see where that stands, and let you know. The goal would definitely be to allow more than just dom events. A proxy should be able to provide a simple I'll try to answer some of your specific questions soon, and give a summary of where things stand. |
No worries @briancavalier, I see you guys have been busy, and I've been quite preoccupied with other things myself. More generic event handling sounds good, we'll need to figure out what the analog of CSS selectors would be for that, if any. Looking forward to your ideas. |
Ok! finally found some time to look back at where I left this, and just pushed the proxy-on branch, which refactors wire/on into a general purpose "on" facet that simply delegates to any component's proxy.on. Dom plugins (like wire/dom and wire/jquery/dom) implement a Proxy for DOM nodes that provides an appropriately implemented Proxy.prototype.on method. Hopefully the proxy-on branch will be a good basis for discussion. In that branch, wire/on considers the "event" parameters to be opaque--it can be anything (string, object, etc.) and will simply be passed through to the proxy's on() method. That means that the onus is on the developer to supply correct information for the particular type of component with which they're using "on". For dom nodes, that's an event type and selector pair, as it was before, eg: "click:.my-button", etc. I can't see any other way to make this work in the general case right now. The wire/on plugin just has to pass through whatever information it is given, and the particular, component-specific proxy has to interpret and translate that information in some implementation-specific way--ie whatever it needs to do in order to hook up an event on the component. Consequently, Proxies should throw if they receive some event specifier that they can't make sense of, in order to tell the developer he/she made a mistake. |
I forgot to mention that the refactoring somewhat (but not completely) breaks the ability to create a partially applied // Say this._listenToClicks was created and injected using `on!click`
this._listenToClicks(aDomNode, function(e) {
console.log('clicked!');
});
aDomNode.click(); // Nothing happens
setTimeout(function() {
aDomNode.click(); // Logs "clicked!"
}, 10); We'll def need to think carefully about whether that is worth the tradeoff. Maybe there is a way to fix it, but it's certainly not obvious to me right now ... maybe @unscriptable will have some ideas. |
This looks very promising, but there's one too many moving pieces right now for me. Which files should I be focusing on to understand what is going on? I'm seeing: wire/on For starters, and I'm not entirely sure how it all fits in together. It seems to me that "lib/plugin-base/on" implements a generic "on-plugin generator", that is meant to take a custom event-handling function and turn it into a wire plugin thing? |
@skiadas Yes, sorry, the branch is still a bit messy, and several of the other "on"-related things can likely just be removed. This new proxy-based model kind of makes them obsolete. I'll try to make some time today to clean up the branch. First, a question: What are the d3 things that you want to connect to? Are they DOM Nodes? Are they d3-specific JS objects? If they are DOM Nodes, then you may not need to do any work at all. Read on, though :) Ok, on to your specific questions:
Basically, yes. In the master and dev branches, that's exactly what
In the old world, yes :) In the proxy-on world, no. In the proxy-on world, for custom d3 events, you will write a wire d3 plugin that provides a proxy for the kind of d3 components to which you would like to connect. By simply implementing the proxy,
Sorry,
The best place to look right now is The first related thing it does is to create a new proxy by inheriting (via standard Object.create technique) from the basic NodeProxy, and implements a custom That last bit deserves just a bit of explanation. Internally, wire creates a base proxy for all components it creates. Plugins may then stack additional functionality onto that using the In your d3 plugin, depending on what your proxy will be proxying (I don't know d3 well enough to know), your d3 proxy will inherit from either NodeProxy (if you will be proxying and connecting to DOM Nodes), or from ObjectProxy if you will be proxying JS Objects. The second related thing To implement a d3 plugin that supports using "on" for event connections with d3-specific components You'll write a wire plugin that:
(See also the Proxy docs) To use your new plugin Once you have your plugin, you can use it in a wire spec:
Sorry to be long winded! Hopefully, some of that was helpful! Like I said, I'll try to clean up the branch a bit more to remove all the "on" noise. |
Hi @briancavalier Basically in d3 you would do something like say: d3.select(aCSSselector), which will look for a set of nodes matching the selector, and create a d3 object that "represents" that collection. A normal course of events would then be to call various d3 methods of that object, one of them being an "on" method, which will effectively register a handler to handle some event on the nodes of the selection. So it sounds to me that your scheme above is more or less what I would need to do. d3 handles those events in a somewhat different way, setting some global values and the "this" object, but I want it to play nice with non-d3 components, and that's mainly where the plugin would be coming in, translating the d3-event into a "normal" dom event that the eventHandlerCallback can understand. In essence, I'd like someone who tries to connect to the d3 object to be able to treat it just as if they were connecting to the DOM node directly. Hm I think I am starting to ramble on, I just wanted to touch base on this and to see if there are any updates before I dig in. |
@skiadas Great! This sounds like it won't be too hard. It seems like we'll need some way to "create a d3 object that "represents" that collection" in wire. One possibility would be for this new d3 wire plugin to expose a factory or a resolver, in addition to the Proxy. In the case of a factory, this may work out quite well as factories are allowed to return a Proxy, which avoids the need to query all currently active plugins looking an appropriate proxy-creating function. Either way, once a d3 object has been created and proxied,
This sounds very interesting. Do you know how "d3 events" differ from "normal" DOM events? I haven't made the time yet to clean up the proxy-on stuff, but I will try to make time over the next couple days. |
A factory is exactly what I had in mind! "d3 events" are described here: Basically, it's not that the events are not regular DOM events, but the expected form of the handlers is completely different. The arguments passed to the handler, instead of the event, are the "datum" and "index" in the collection associated with the DOM element that triggered the event. So the handler that you would normally provide to aD3object.on would have the form function(d,i) {}. Also this handler is called with "this" set to the dom element that triggered the event. The handler is supposed to access the event by accessing the "event" property of the global d3 object, namely d3.event (https://github.com/mbostock/d3/wiki/Selections#d3_event). It is important that this property is set, as it enables a number of other d3 functionality. So I am thinking my proxy object would need to take a handler with a signature of function(event,element){} or something of the sort, and create a "d3-handler" wrapper around it, then pass that wrapper to the aD3object.on method. Haven't fully worked out the details yet. I'm thinking I could expose a "d3on" facet, distinct from "on", that allows handlers to be attached that use the d3-event form instead of the standard DOM-event form. This way d3-components would be able to place nicer with each other, while still being able to connect to non-d3 components. But that's another matter. |
@briancavalier "In the case of a factory, this may work out quite well as factories are allowed to return a Proxy". Can you elaborate on this?
|
See #108. Opening this specifically to discuss implementing
Proxy.on
as an API to allow a proxy to implement event handling that is specific to the type of component it is proxying. There are many custom event systems, and this would help wire adapt to them while also providing a consistent interface for developers viawire/on
.The text was updated successfully, but these errors were encountered: