From: Kevin Carhart <kevin@carhart.net>
To: Edbrowse-dev@lists.the-brannons.com
Subject: Re: [Edbrowse-dev] data-* attributes / new work on RC
Date: Sun, 26 Nov 2017 17:03:38 -0800 (PST) [thread overview]
Message-ID: <alpine.LRH.2.03.1711261521280.28077@carhart.net> (raw)
In-Reply-To: <20171026081440.eklhad@comcast.net>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 11092 bytes --]
> After browsing the home page, I set db4 and went to the Our Ship link,
I think there are strands of a couple of causes at once, maybe.
I recognize preventDefault. This has to do with Event.
If you clone https://github.com/thatcher/env-js.git
and go to src/event/event.js , preventDefault is here. It has to do with
bubbling/capturing, which is what that third argument to addEventHandler
is about. And this env code is where I got the Event = function(){
definition from.
I think we want eb$master.Event.prototype.preventDefault, and maybe some
others like eb$master.Event.prototype.stopPropagation. But this raises
the question of bubbling & capturing. I think that's what radiocaroline
is trying to call preventDefault for. I'm going to include an article that MDN
links, because it seems like useful history. If we understand this
theme, maybe we ought to revisit that third argument to addEventListener,
which if you remember we currently set aside and call it 'notused'.
The author is Peter-Paul Koch and the article is at
https://www.quirksmode.org/js/events_order.html
---
Netscape 4 only supports event capturing, Explorer only supports event
bubbling. Netscape 6 and Konqueror support both, while Opera and iCab
support neither.
On the Introduction to events page I asked a question that at first sight
seems incomprehensible: “If an element and one of its ancestors have an
event handler for the same event, which one should fire first?” Not
surprisingly, this depends on the browser.
The basic problem is very simple. Suppose you have a element inside an
element and both have an onClick event handler. If the user clicks on
element2 he causes a click event in both element1 and element2. But which
event fires first? Which event handler should be executed first? What, in
other words, is the event order?
Two models
Not surprisingly, back in the bad old days Netscape and Microsoft came to
different conclusions.
Netscape said that the event on element1 takes place first. This is
called event capturing.
Microsoft maintained that the event on element2 takes precedence. This
is called event bubbling.
The two event orders are radically opposed. Explorer only supports event
bubbling. Mozilla, Opera 7 and Konqueror support both. Older Opera's and
iCab support neither.
Event capturing
When you use event capturing
[arrow pointing DOWN from element1 to element2]
the event handler of element1 fires first, the event handler of element2
fires last.
Event bubbling
When you use event bubbling
[diagram with an arrow pointing up from element2 , then element1]
the event handler of element2 fires first, the event handler of element1
fires last.
W3C model
W3C has very sensibly decided to take a middle position in this struggle.
Any event taking place in the W3C event model is first captured until it
reaches the target element and then bubbles up again.
[diagram that says "W3C event model." First there's an arrow going down
the tree from e1 to e2, and then a second arrow coming up from e2 to e1.]
You, the web developer, can choose whether to register an event handler in
the capturing or in the bubbling phase. This is done through the
addEventListener() method explained on the Advanced models page. If its
last argument is true the event handler is set for the capturing phase, if
it is false the event handler is set for the bubbling phase.
Suppose you do
element1.addEventListener('click',doSomething2,true)
element2.addEventListener('click',doSomething,false)
If the user clicks on element2 the following happens:
The click event starts in the capturing phase. The event looks if any
ancestor element of element2 has a onclick event handler for the capturing
phase.
The event finds one on element1. doSomething2() is executed.
The event travels down to the target itself, no more event handlers
for the capturing phase are found. The event moves to its bubbling phase
and executes doSomething(), which is registered to element2 for the
bubbling phase.
The event travels upwards again and checks if any ancestor element of
the target has an event handler for the bubbling phase. This is not the
case, so nothing happens.
The reverse would be
element1.addEventListener('click',doSomething2,false)
element2.addEventListener('click',doSomething,false)
Now if the user clicks on element2 the following happens:
The click event starts in the capturing phase. The event looks if any
ancestor element of element2 has a onclick event handler for the capturing
phase and doesn’t find any.
The event travels down to the target itself. The event moves to its
bubbling phase and executes doSomething(), which is registered to element2
for the bubbling phase.
The event travels upwards again and checks if any ancestor element of
the target has an event handler for the bubbling phase.
The event finds one on element1. Now doSomething2() is executed.
Compatibility with traditional model
In the browsers that support the W3C DOM, a traditional event registration
element1.onclick = doSomething2;
is seen as a registration in the bubbling phase.
Use of event bubbling
Few web developers consciously use event capturing or bubbling. In Web
pages as they are made today, it is simply not necessary to let a bubbling
event be handled by several different event handlers. Users might get
confused by several things happening after one mouse click, and usually
you want to keep your event handling scripts separated. When the user
clicks on an element, something happens, when he clicks on another
element, something else happens.
Of course this might change in the future, and it’s good to have models
available that are forward compatible. But the main practical use of event
capturing and bubbling today is the registration of default functions.
It always happens
What you first need to understand is that event capturing or bubbling
always happens. If you define a general onclick event handler for your
entire document
document.onclick = doSomething;
if (document.captureEvents) document.captureEvents(Event.CLICK);
any click event on any element in the document will eventually bubble up
to the document and thus fire this general event handler. Only when a
previous event handling script explicitly orders the event to stop
bubbling, it will not propagate to the document.
Uses
Because any event ends up on the document, default event handlers become
possible. Suppose you have this page:
[diagram of a document object with childNodes element1 and element2]
element1.onclick = doSomething;
element2.onclick = doSomething;
document.onclick = defaultFunction;
Now if the user clicks on element1 or 2, doSomething() is executed. You
can stop the event propagation here, if you wish. If you don’t the event
bubbles up to defaultFunction(). If the user clicks anywhere else
defaultFunction() is also executed. This might be useful sometimes.
Setting document–wide event handlers is necessary in drag–and–drop
scripts. Typically a mousedown event on a layer selects this layer and
makes it respond to the mousemove event. Though the mousedown is usually
registered on the layer to avoid browser bugs, both other event handlers
must be document–wide.
Remember the First Law of Browserology: anything can happen, and it
usually does when you’re least prepared for it. So it may happen that the
user moves his mouse very wildly and the script doesn’t keep up so that
the mouse is not over the layer any more.
If the onmousemove event handler is registered to the layer, the layer
doesn’t react to the mouse movement any more, causing confusion.
If the onmouseup event handler is registered on the layer, this event
isn’t caught either so that the layer keeps reacting to the mouse
movements even after the user thinks he dropped the layer. This causes
even more confusion.
So in this case event bubbling is very useful because registering your
event handlers on document level makes sure they’re always executed.
Turning it off
But usually you want to turn all capturing and bubbling off to keep
functions from interfering with each other. Besides, if your document
structure is very complex (lots of nested tables and such) you may save
system resources by turning off bubbling. The browser has to go through
every single ancestor element of the event target to see if it has an
event handler. Even if none are found, the search still takes time.
In the Microsoft model you must set the event’s cancelBubble property to
true.
window.event.cancelBubble = true
In the W3C model you must call the event’s stopPropagation() method.
e.stopPropagation()
This stops all propagation of the event in the bubbling phase. For a
complete cross-browser experience do
function doSomething(e)
{
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}
Setting the cancelBubble property in browsers that don’t support it
doesn’t hurt. The browser shrugs and creates the property. Of course it
doesn’t actually cancel the bubbling, but the assignment itself is safe.
currentTarget
As we’ve seen earlier, an event has a target or srcElement that contains a
reference to the element the event happened on. In our example this is
element2, since the user clicked on it.
It is very important to understand that during the capturing and bubbling
phases (if any) this target does not change: it always remains a reference
to element2.
But suppose we register these event handlers:
element1.onclick = doSomething;
element2.onclick = doSomething;
If the user clicks on element2 doSomething() is executed twice. But how do
you know which HTML element is currently handling the event?
target/srcElement don’t give a clue, they always refer to element2 since
it is the original source of the event.
To solve this problem W3C has added the currentTarget property. It
contains a reference to the HTML element the event is currently being
handled by: exactly what we need. Unfortunately the Microsoft model
doesn’t contain a similar property.
You can also use the this keyword. In the example above it refers to the
HTML element the event is handled on, just like currentTarget.
Problems of the Microsoft model
But when you use the Microsoft event registration model the this keyword
doesn’t refer to the HTML element. Combined with the lack of a
currentTarget–like property in the Microsoft model, this means that if you
do
element1.attachEvent('onclick',doSomething)
element2.attachEvent('onclick',doSomething)
you cannot know which HTML element currently handles the event. This is
the most serious problem with the Microsoft event registration model and
for me it’s reason enough never to use it, not even in IE/Win only
applications.
I hope Microsoft will soon add a currentTarget–like property — or maybe
even follow the standard? Web developers need this information.
next prev parent reply other threads:[~2017-11-27 1:02 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-16 12:29 [Edbrowse-dev] Tidy error reporting Karl Dahlke
2017-11-22 8:43 ` [Edbrowse-dev] data-* attributes Kevin Carhart
2017-11-22 9:33 ` Kevin Carhart
2017-11-22 15:48 ` Karl Dahlke
2017-11-22 21:36 ` Kevin Carhart
2017-11-23 1:23 ` Kevin Carhart
2017-11-24 21:19 ` Karl Dahlke
2017-11-25 0:20 ` [Edbrowse-dev] data-* attributes / new work on RC Kevin Carhart
2017-11-25 0:56 ` Karl Dahlke
2017-11-25 1:15 ` Kevin Carhart
2017-11-25 1:22 ` Karl Dahlke
2017-11-25 1:44 ` Kevin Carhart
2017-11-25 2:28 ` Karl Dahlke
2017-11-25 3:10 ` Kevin Carhart
2017-11-25 5:02 ` Karl Dahlke
2017-11-25 5:35 ` Kevin Carhart
2017-11-26 13:14 ` Karl Dahlke
2017-11-27 1:03 ` Kevin Carhart [this message]
2017-11-27 1:48 ` Kevin Carhart
2017-11-27 2:58 ` Karl Dahlke
2017-11-27 3:37 ` Kevin Carhart
2017-11-26 22:43 ` Karl Dahlke
2017-11-27 3:19 ` Kevin Carhart
2017-11-27 4:23 ` Karl Dahlke
2017-11-27 4:51 ` Kevin Carhart
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=alpine.LRH.2.03.1711261521280.28077@carhart.net \
--to=kevin@carhart.net \
--cc=Edbrowse-dev@lists.the-brannons.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).