This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 26892 - [Shadow]: Consider not using AT_TARGET more than once in the event path
Summary: [Shadow]: Consider not using AT_TARGET more than once in the event path
Status: RESOLVED MOVED
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: HISTORICAL - Component Model (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Dimitri Glazkov
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
: 28246 (view as bug list)
Depends on:
Blocks: 28552 28564
  Show dependency treegraph
 
Reported: 2014-09-23 15:36 UTC by Dimitri Glazkov
Modified: 2015-05-27 03:21 UTC (History)
6 users (show)

See Also:


Attachments

Description Dimitri Glazkov 2014-09-23 15:36:32 UTC
I was wrong in bug 15543. The effect of invoking event listeners with AT_TARGET at each shadow host along the event path is that even non-bubbling events appear to bubble.

This is especially evident in situations where logical units of an application are composed using Shadow DOM. Here's a simple example:

I am building a grocery list app. Suppose I am currently making the grocery list editor. The EDIT ITEM dialog box is in its own shadow tree. Inside of this box, I have input fields, as well as a CANCEL button and a DELETE button. 

Clicking CANCEL fires a simple 'cancel' event on the EDIT ITEM's shadow host. The event is meant to be listened to by the owner of the EDIT ITEM dialog box (to close it, presumably).

Clicking DELETE opens another CONFIRM DELETE dialog (also in a shadow tree) on top of the EDIT ITEM dialog. That dialog has OK and CANCEL as well.

Suppose that I repeat my event pattern on the CONFIRM DELETE dialog. Clicking CANCEL there fires a simple 'cancel' event. The idea is that my EDIT ITEM dialog can listen to this event and close the CONFIRM DELETE dialog.

Sounds simplistic enough, right? Here's where things get interesting. 

Unfortunately for me, when I click on CANCEL in the CONFIRM DELETE dialog, my EDIT ITEM dialog goes away as well!

The reason for this strange occurrence is because, despite 'cancel' being a simple event, the AT_TARGET listener invocation occurs both at the CONFIRM DELETE shadow host and at the EDIT ITEM shadow host.

In other words, the bubbling event listener that is only supposed to hear EDIT ITEM's 'cancel' event will also hear the CONFIRM DELETE's 'cancel' event -- even though I, the developer, specifically told this event not to bubble.

Now I have no choice but work around this problem by attempting to distinguish different 'cancel' events that are coming through.

I think the solution to this conundrum is the same as the one for the bug 20247.
Comment 1 Olli Pettay 2014-09-23 16:26:29 UTC
No, events don't appear as bubbling in the scope of the host. What happens
under the host doesn't matter. If a "cancel" is dispatched there, then
it is supposed to look like its target is actually the host.

Capturing event listeners should fire during capture phase, and
phase should be at_target is currentTarget == target.
bubbling event listeners would then fire during bubble phase, and
phase would be at_target when currentTarget == target.

I don't quite see what bubbling actually have to do with your example.
What if web page uses capturing listeners? You'd have the same issue even
if bubbling would stop earlier.

What we may need is some way to say that events x,y,z shouldn't propagate out from the shadow dom, either in capture or bubble phase.
Comment 2 Dimitri Glazkov 2014-09-24 16:23:18 UTC
(In reply to Olli Pettay from comment #1)
> No, events don't appear as bubbling in the scope of the host. What happens
> under the host doesn't matter. If a "cancel" is dispatched there, then
> it is supposed to look like its target is actually the host.
> 
> Capturing event listeners should fire during capture phase, and
> phase should be at_target is currentTarget == target.
> bubbling event listeners would then fire during bubble phase, and
> phase would be at_target when currentTarget == target.

Yes, this is all good. I was there, remember? :)

> 
> I don't quite see what bubbling actually have to do with your example.
> What if web page uses capturing listeners? You'd have the same issue even
> if bubbling would stop earlier.

Take your browser eng hat off for a minute and put your average webdev hat on.

As an average web dev, you only have a vague idea what the hell capturing listener is. You mostly do element.addEventListener(name, handler).

So you have this app structure (idealized/simplified):

grocery-app.html:
...
<edit-grocery-item-dialog>
  #shadow-root
    ...
    <confirm-delete-dialog>
      #shadow-root
        ...
...

<script>

...

var editGroceryItem = document.querySelector('edit-grocery-item-dialog');
editGroceryItem.addEventListener('cancel', function() {
  console.log('CANCEL: closing edit grocery item!');
  ...
});

...

var confirmDelete = editGroceryItem.shadowRoot.querySelector('confirm-delete-dialog');
confirmDelete.addEventListener('cancel', function() {
  console.log('CANCEL: closing confirm!');
});

...

// when CANCEL button in the confirm delete dialog is clicked...
buttonInsideConfirmDeleteDialog.dispatchEvent(new CustomEvent('cancel'));

</script>

Now, as a webdev, you'll be surprised (and probably frustrated) to find out that you ALWAYS get both event handlers invoked when you click on the cancel delete button. You'll be like "whaaa? I just wanted to close the confirm delete dialog. You stupid SOB, why are also closing my edit item dialog?"

The web developer's expectation that the event doesn't bubble, and that whole AT_TARGET mumbo jumbo that you and I are painfully aware of is but a faint nagging feeling that something's gone terribly wrong.

> 
> What we may need is some way to say that events x,y,z shouldn't propagate
> out from the shadow dom, either in capture or bubble phase.

Yes! That's what I said in the first comment! :)
Comment 3 Olli Pettay 2014-09-24 16:33:09 UTC
(In reply to Dimitri Glazkov from comment #2)
> > 
> > What we may need is some way to say that events x,y,z shouldn't propagate
> > out from the shadow dom, either in capture or bubble phase.
> 
> Yes! That's what I said in the first comment! :)
I don't see it mentioned in the first comment ;)

I'm thinking some API like
interface ShadowRoot {
  ...

  void setEncapsulatedEvents(sequence<DOMString> types);
}
That would prevent propagation of those events in case the event is originally
from somewhere under the shadow tree (i.e. shadowhost.contains(event.target) would return false or so)
Comment 4 Olli Pettay 2014-09-24 16:34:07 UTC
And yes, the method name in the example is horrible, something better should be used.
Comment 5 Hayato Ito 2015-04-22 22:29:23 UTC
If we are pursuing something like "void setEncapsulatedEvents(sequence<DOMString> types)", can we merge this issue to https://www.w3.org/Bugs/Public/show_bug.cgi?id=20247 ?

I think both topics are related. I'd like to have one good idea which resolves both.
Comment 6 Dimitri Glazkov 2015-04-23 18:21:42 UTC
*** Bug 28246 has been marked as a duplicate of this bug. ***
Comment 7 Hayato Ito 2015-05-27 03:21:24 UTC
Moved to https://github.com/w3c/webcomponents/issues/68