Specifically Spidermonkey.
I know you write functions and attach them to events to handle them.
Where is the onClick handler defined and how does the JS engine know to fire onClick events when the user clicks?
Any keywords, design patterns, links, etc are appreciated.
UPDATE
Aggregating links I find useful here:
http://www.w3.org/TR/DOM-Level-2-Events/events.html
https://github.com/joyent/node/blob/master/src/node_events.cc
http://mxr.mozilla.org/mozilla/source/dom/src/events/nsJSEventListener.cpp
SpiderMonkey itself doesn't have anything involving event handling. Events are purely a DOM thing.
The click event is fired by the browser code (the thing embedding SpiderMonkey), not by SpiderMonkey itself. See http://hg.mozilla.org/mozilla-central/file/e60b8be7a97b/content/events/src/nsEventStateManager.cpp for the code that's responsible for dispatching things like click.
The browser is also what defines setter methods that take an assignment to the onclick property and turn it into an event listener registration. See http://hg.mozilla.org/mozilla-central/file/e60b8be7a97b/dom/base/nsDOMClassInfo.cpp#l7624 which is called from nsEventReceiverSH::SetProperty and handles properties whose name (id in this code) passes the IsEventName test.
When event listeners are registered and an event is fired, the event dispatcher manages calls to the listeners; the nsJSEventListener link you found is the glue that converts a C++ HandleEvent call into a call to a JS function.
So in your case, you want some sort of registration/unregistration mechanism for listeners and then your implementation will fire events and dispatch them to listeners. How you do this last part is pretty open-ended; the Gecko implementation has a lot of constraints due to needing to implement the DOM Events specification, but you should be able to do something much simpler.
HTML uses sink/bubble event propagation schema: http://catcode.com/domcontent/events/capture.html
There are "physical" events (mouse, keyboard) and logical/synthesized ones (focus,click, value_changed, etc.)
onClick is a logical event - generated as a result of mouse, touch and/or keyboard events.
Mouse (or finger touch) originated click event is a result of mouse down, move and up events. Note that mouse down, move and up are sinking/bubbling events. Target element(s) in these "primordial" events will be the target(or source) of the click event. If mouse-down/up events have different targets (DOM element) then their common parent is used.
Sequence of mouse down, move and up events may produce different logical events: click, swipe/scroll, etc.
I believe this is a full list of basic concepts.
Related
Are events in JavaScript always fired even if there are no listeners attached?
Lets say "mousemove", I move the mouse but there are no listeners in the whole app, will the browser still construct a new Event and fire it, or will it optimize and consider the fact that if there are no event listeners, just ignore the data.
I assume that each browser works differently and I'm assuming they use patterns like observer and what not, but is there a spec around that states how it should be?
Feel free to downvote this if you feel this is not correct but from my understanding and according to the DOM Level 2 Events Spec there is a sense that events are always constructed and executed but listeners need to be there, of course, to actually register them.
The reason I say "there is a sense that events are always constructed and executed" is because the Spec mentions that
This method allows the registration of event listeners on the event
target. If an EventListener is added to an EventTarget while it is
processing an event, it will not be triggered by the current actions
but may be triggered during a later stage of event flow, such as the
bubbling phase. If multiple identical EventListeners are registered on
the same EventTarget with the same parameters the duplicate instances
are discarded. They do not cause the EventListener to be called twice
and since they are discarded they do not need to be removed with the
removeEventListener method.
So if event listeners are dynamically added, there needs to be a way for the the page to know to register and listen to them. How each browser handles this is probably different as #JAAulde mentioned above but I do not think browsers would optimize for the fact that an event listener exists or not or at least nothing drastic.
I am new to jQuery and I have been trying to look up the Bootstrap transition.js (line 50) code and figure out how it works in there. I have stumbled across the following:
$.event.special.bsTransitionEnd = {
bindType: $.support.transition.end,
delegateType: $.support.transition.end,
handle: function (e) {
if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
}
I have read the documentation, but couldn't really understand much except the following:
bindType: // the event you want to bind with
delegateType: // the event you want to delegate with
After some research I have found the following:
Those are the special attributes for the transition end event that are made available for later use in transition.js.
I am trying to figure out things by reading this article, but all I want to know is: what is $.event.special, what is the use of this line? What is it's common usage?
P.S.: I read this question but it has more external links than the answer itself. Is there a clear canonical Q&A about the most basic use of $.event.special?
WHAT is the use of this line?
I'm assuming you meant the first line of code in your question. It basically defines bsTransitionEnd as an alias for the transition end event (the transition end event may vary from browser to browser - that is what the function transitionEnd() does : determine the proper transition end event for the browser. I've used webkitTransitionEnd here on, but it could be something else depending on the browser)
Why use an alias? It insulates any handlers that Bootstrap attaches using this alias (e.g. $('myBootstrapDialog').on('bsTransitionEnd', Bootstrap's handler) from any $('myBootstrapDialog').off('webkitTransitionEnd') that other code (say, your code or maybe another library) does - so the Bootstrap transition end animations would still work!
Why would you or another library do that? The webkitTransitionEnd is a standard event, so let's say you decide to add a transition end animation to a bootstrap dialog - you'd probably do $('myBootstrapDialog').on('webkitTransitionEnd', your handler) and later on you decide to remove the handler you should be going $('myBootstrapDialog').off('webkitTransitionEnd', your handler), but you miscode it as $('myBootstrapDialog').off('webkitTransitionEnd') - this removes all transition end events :-(.
But since Bootstrap attached it's handlers using 'bsTransitionEnd', the only way you could mess up bootstrap would be to do $('myBootstrapDialog').off('bsTransitionEnd') - not something you would do accidentally :-). So voila! Gone be the bugs where Bootstrap inexplicably stops working because of some small miscoding on your part.
The bindType and delegateType basically state that bsTransitionEnd is an alias for transition events attached directly, and ones that are delegated (bubbles). The handle is basically a filter function - all the triggered events basically go through this before the attached Bootstrap event handlers are called (if at all they are)
what is $.event.special?
I'm sure you'd know most of it already - it's a way to hook into jQuery's event handling mechanism allowing you do large scale magic like do X on every attached click event on the page (imagine doing that one by one, at each and every place you've attached an onclick event), define your own events (with all the bubbly goodness and all which comes with it), hook in and spoof events by modifying the event object, etc.
WHAT is its common usage?
I assume this was rhetorical :-) - you already have a couple of really good examples in the Ben Alman blog post you linked to
(paraphrasing) - let's say you do an AJAX submit and want to disable all clicks on the page (you probably don't want the user clicking on and navigating off to some other page via a menu, or changing a checkbox, etc.) and $.event.special.click should help you (of course it might be just easier / traditional to just overlay a transparent / partially transparent div with a Submitting... animation or something or not doing anything - after all, most users wait around to make sure a submit was successful, at least the normal ones :-))
Another use case is the one you saw in the bootstrap code, but like you mentioned, you usually don't have to go in and use this unless you're writing a library or something that you intend to distribute publicly.
$.event.special
The jQuery special events API is a fairly flexible system by which you can specify bind and unbind hooks as well as default actions for custom events. In using this API, you can create custom events that do more than just execute bound event handlers when triggered--these "special" events can modify the event object passed to event handlers, trigger other entirely different events, or execute complex setup and teardown code when event handlers are bound to or unbound from elements.
The jQuery special event hooks are a set of per-event-name functions and properties that allow code to control the behavior of event processing within jQuery. The mechanism is similar to fixHooks in that the special event information is stored injQuery.event.special.NAME, where NAME is the name of the special event. Event names are case sensitive.
As with fixHooks, the special event hooks design assumes it will be very rare that two unrelated pieces of code want to process the same event name. Special event authors who need to modify events with existing hooks will need to take precautions to avoid introducing unwanted side-effects by clobbering those hooks
bindType: // the event you want to bind with
delegateType: // the event you want to delegate with
When defined bindType: String, delegateType: String, these string properties specify that a special event should be handled like another event type until the event is delivered. The bindType is used if the event is attached directly, and the delegateType is used for delegated events. These types are generally DOM event types, and should not be a special event themselves.
The addEventListener DOM method supports a third optional, boolean parameter (useCapture) to indicate whether the function should use event bubbling or event capturing as propagation method. In this article the difference is nicely shown (click on the examples & view code).
From other questions on SO and blog posts, I concluded event bubbling was preferred mostly because IE8- didn't support it.
Suppose I'm only required to support IE9+, in what situation would event capturing be necessary or preferred over event bubbling? In other words, in what situation would it be better to let the events execute on the outermost elements first, and then the innermost elements? I'm looking for a simple, real world example to demonstrate the use of event capturing...
Event capturing used to be the only option outside of the Internet Explorer browser:
One of the major differences of the back then two important browsers was how they handled events. Microsoft worked with the bubbling phase - meaning the event first hit on the target element and then traverse the whole DOM upwards hitting on the parent nodes whereas Netscape did it the exact other way - meaning the event first passes the parent elements and then runs down to the target element - capturing. This caused developers in the early days a lot of trouble and the W3C finally specified an approach where both kind of works and can be used at free will.
Event capturing is useful in event delegation when bubbling is not supported. For example:
Some events, such as focus, don't bubble but can be captured.
The inline handler on the target element triggers before capture handlers for the target element.
Many newly specified events in the web platform (such as the media events) do not bubble, which is a problem for frameworks like Ember that rely on event delegation. However, the capture API, which was added in IE9, is invoked properly for all events, and does not require a normalization layer. Not only would supporting the capture API allow us to drop the jQuery dependency, but it would allow us to properly handle these non-bubbling events. This would allow you to use events like playing in your components without having to manually set up event listeners.
Custom events and bubbling have the following issues:
Currently, Ember relies on jQuery for event handling, doing so comes with several costs:
jQuery silently changes inline handlers to bubble handlers.
This changes expected invocation order
This can cause automated tests to fail
Events triggered via jQuery.trigger trigger handlers in a different order than events triggered by a user.
This changes expected invocation order
This leads to difficult to reason about and debug aberrations in behavior
This often causes automated tests to fail
Events must flow down and bubble back up through the entire DOM before being detected by the Ember application, and then must undergo an expensive delegation process that is effectively re-bubbling to find the right handler.
Handlers attached directly within components or by non-ember plugins take precedent over handlers attached by Ember, whether this was desired or not.
This causes component handlers to have far-reaching side-effects
This leads to difficult to reason about and debug aberrations in behavior
This often causes automated tests to fail
A media player focus=>play preprocess/postprocess event flow would be a simple use case.
The mechanics of the capturing phase make it ideal for preparing or preventing behavior that will later be applied by event delegation during the bubbling phase. And that’s how we’re going to use it here—to initialize the sortable in response to a mouse click, but just before the event starts bubbling and other handlers have a chance to deal with it.
To make use of capturing, we have to go down to the metal. jQuery’s event methods only work for bubbling and don’t let us tap into the capturing phase. The capturing handler looks like:
document.addEventListener("mousedown", function(event) {
if ($(event.target).closest(".sortable_handle").length) {
$("article.todolist, section.todolists").sortable();
}
}, true);
References
Domina Github Repo: Readme - Event Propagation
EmberJS RFC: Capture Based Eventing
EmberJS RFC: Internet Explorer
MDN: Event.eventPhase
Using event capturing to improve Basecamp page load times – Signal v. Noise
Bubbling, foreign events and Firefox: Index
Event capture and bubbling
There are more custom onclick events on a page. I want for every custom onclick event to first prevent the default, do my things and then pass the command to the first custom event.
In other words I want to put my event on top of any other assigned click events. How can I do that?
You may see this answer.
OR
Refering to this explanation you can choose where to get involved in the event-dispatching-process.
It states clearly
In the browsers that support the W3C DOM, a traditional event registration
element1.onclick = doSomething2;
is seen as a registration in the bubbling phase.
So you have to hook into the capturing phase:
element.addEventListener('click', function() {
//do your stuff
},true);
This way your event is on top of other assigned click events.
But it is still a question, if the browser supports this kind of event handling.
I figure other developers have run into this before. We have a large code base with many components following this pattern:
$('#elm').on('click',function($e){
$e.stopPropagation();
//... do stuff (i.e. Open something);
});
$('html').on('click',function($e){
//... do oposite of stuff (i.e. Close something);
}
Our issue is, all the stopPropagation's across the site are stopping closing of other components. What we really want is a mechanism to only block the click handler for this component but not for others.
I'm looking for a solution which is the easiest to implement right now to fix our bugs and for our Multi-developer team to follow in the future.
The .live() method handles events once they have propagated to the top of the document, it is not possible to stop propagation using live events this allows you to do hack and take advantage of this because the .live() method binds a handler to the $(document), and identifies which element triggered the event up at the top of the hierarchy using the event.target property.
The stopPropagation stops the propagation from bubbling up the DOM hierarchy, but since the handler is at the document level there is no upper place to propogate to.
On the other hand note that events handled by .delegate() will bubble up to the elements to which they are binded to; event handlers bound on any elements below it in the DOM tree will already have been executed by the time the delegated event handler is called. These handlers, therefore, may prevent the delegated handler from triggering by calling event.stopPropagation()
See this example: http://jsfiddle.net/knr3v/2/
Therefore you can use the live and delegate method instead of click, bind, on method to do exactly what you are explaining.