mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 887541 - Implement web components event path and event retargeting. r=smaug
This commit is contained in:
parent
8b3951c20f
commit
e50e0d25cd
@ -214,7 +214,8 @@ public:
|
||||
const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
|
||||
|
||||
/**
|
||||
* Similar to ContentIsDescendantOf except it crosses document boundaries.
|
||||
* Similar to ContentIsDescendantOf except it crosses document boundaries,
|
||||
* also crosses ShadowRoot boundaries from ShadowRoot to its host.
|
||||
*/
|
||||
static bool ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
|
||||
nsINode* aPossibleAncestor);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "nsDOMAttributeMap.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "mozilla/dom/NodeInfo.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "nsIDocumentInlines.h"
|
||||
#include "nsIDocumentEncoder.h"
|
||||
#include "nsIDOMNodeList.h"
|
||||
@ -698,14 +699,27 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
aVisitor.mEvent->message == NS_POINTER_OUT) &&
|
||||
// Check if we should stop event propagation when event has just been
|
||||
// dispatched or when we're about to propagate from
|
||||
// chrome access only subtree.
|
||||
// chrome access only subtree or if we are about to propagate out of
|
||||
// a shadow root to a shadow root host.
|
||||
((this == aVisitor.mEvent->originalTarget &&
|
||||
!ChromeOnlyAccess()) || isAnonForEvents)) {
|
||||
!ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
|
||||
nsCOMPtr<nsIContent> relatedTarget =
|
||||
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget);
|
||||
if (relatedTarget &&
|
||||
relatedTarget->OwnerDoc() == OwnerDoc()) {
|
||||
|
||||
// In the web components case, we may need to stop propagation of events
|
||||
// at shadow root host.
|
||||
if (GetShadowRoot()) {
|
||||
nsIContent* adjustedTarget =
|
||||
Event::GetShadowRelatedTarget(this, relatedTarget);
|
||||
if (this == adjustedTarget) {
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
aVisitor.mCanHandle = false;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// If current target is anonymous for events or we know that related
|
||||
// target is descendant of an element which is anonymous for events,
|
||||
// we may want to stop event propagation.
|
||||
@ -769,6 +783,99 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
}
|
||||
|
||||
nsIContent* parent = GetParent();
|
||||
|
||||
// Web components have a special event chain that need to account
|
||||
// for destination insertion points where nodes have been distributed.
|
||||
nsTArray<nsIContent*>* destPoints = GetExistingDestInsertionPoints();
|
||||
if (destPoints && !destPoints->IsEmpty()) {
|
||||
// Push destination insertion points to aVisitor.mDestInsertionPoints
|
||||
// excluding shadow insertion points.
|
||||
bool didPushNonShadowInsertionPoint = false;
|
||||
for (uint32_t i = 0; i < destPoints->Length(); i++) {
|
||||
nsIContent* point = destPoints->ElementAt(i);
|
||||
if (!ShadowRoot::IsShadowInsertionPoint(point)) {
|
||||
aVisitor.mDestInsertionPoints.AppendElement(point);
|
||||
didPushNonShadowInsertionPoint = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Next node in the event path is the final destination
|
||||
// (non-shadow) insertion point that was pushed.
|
||||
if (didPushNonShadowInsertionPoint) {
|
||||
parent = aVisitor.mDestInsertionPoints.LastElement();
|
||||
aVisitor.mDestInsertionPoints.SetLength(
|
||||
aVisitor.mDestInsertionPoints.Length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this);
|
||||
if (thisShadowRoot) {
|
||||
// The following events must always be stopped at the root node of the node tree:
|
||||
// abort
|
||||
// error
|
||||
// select
|
||||
// change
|
||||
// load
|
||||
// reset
|
||||
// resize
|
||||
// scroll
|
||||
// selectstart
|
||||
bool stopEvent = false;
|
||||
switch (aVisitor.mEvent->message) {
|
||||
case NS_IMAGE_ABORT:
|
||||
case NS_LOAD_ERROR:
|
||||
case NS_FORM_SELECTED:
|
||||
case NS_FORM_CHANGE:
|
||||
case NS_LOAD:
|
||||
case NS_FORM_RESET:
|
||||
case NS_RESIZE_EVENT:
|
||||
case NS_SCROLL_EVENT:
|
||||
stopEvent = true;
|
||||
break;
|
||||
case NS_USER_DEFINED_EVENT:
|
||||
if (aVisitor.mDOMEvent) {
|
||||
nsAutoString eventType;
|
||||
aVisitor.mDOMEvent->GetType(eventType);
|
||||
if (eventType.EqualsLiteral("abort") ||
|
||||
eventType.EqualsLiteral("error") ||
|
||||
eventType.EqualsLiteral("select") ||
|
||||
eventType.EqualsLiteral("change") ||
|
||||
eventType.EqualsLiteral("load") ||
|
||||
eventType.EqualsLiteral("reset") ||
|
||||
eventType.EqualsLiteral("resize") ||
|
||||
eventType.EqualsLiteral("scroll") ||
|
||||
eventType.EqualsLiteral("selectstart")) {
|
||||
stopEvent = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (stopEvent) {
|
||||
// If we do stop propagation, we still want to propagate
|
||||
// the event to chrome (nsPIDOMWindow::GetParentTarget()).
|
||||
// The load event is special in that we don't ever propagate it
|
||||
// to chrome.
|
||||
nsCOMPtr<nsPIDOMWindow> win = OwnerDoc()->GetWindow();
|
||||
EventTarget* parentTarget = win && aVisitor.mEvent->message != NS_LOAD
|
||||
? win->GetParentTarget() : nullptr;
|
||||
|
||||
aVisitor.mParentTarget = parentTarget;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aVisitor.mDestInsertionPoints.IsEmpty()) {
|
||||
parent = aVisitor.mDestInsertionPoints.LastElement();
|
||||
aVisitor.mDestInsertionPoints.SetLength(
|
||||
aVisitor.mDestInsertionPoints.Length() - 1);
|
||||
} else {
|
||||
// The pool host for the youngest shadow root is shadow DOM host,
|
||||
// for older shadow roots, it is the shadow insertion point
|
||||
// where the shadow root is projected, nullptr if none exists.
|
||||
parent = thisShadowRoot->GetPoolHost();
|
||||
}
|
||||
}
|
||||
|
||||
// Event may need to be retargeted if this is the root of a native
|
||||
// anonymous content subtree or event is dispatched somewhere inside XBL.
|
||||
if (isAnonForEvents) {
|
||||
@ -804,7 +911,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
if (parent) {
|
||||
aVisitor.mParentTarget = parent;
|
||||
} else {
|
||||
aVisitor.mParentTarget = GetCurrentDoc();
|
||||
aVisitor.mParentTarget = GetComposedDoc();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2082,6 +2082,13 @@ nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
|
||||
do {
|
||||
if (aPossibleDescendant == aPossibleAncestor)
|
||||
return true;
|
||||
|
||||
// Step over shadow root to the host node.
|
||||
ShadowRoot* shadowRoot = ShadowRoot::FromNode(aPossibleDescendant);
|
||||
if (shadowRoot) {
|
||||
aPossibleDescendant = shadowRoot->GetHost();
|
||||
}
|
||||
|
||||
aPossibleDescendant = GetCrossDocParentNode(aPossibleDescendant);
|
||||
} while (aPossibleDescendant);
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "base/basictypes.h"
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
@ -1119,6 +1120,44 @@ Event::SetOwner(mozilla::dom::EventTarget* aOwner)
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
nsIContent*
|
||||
Event::GetShadowRelatedTarget(nsIContent* aCurrentTarget,
|
||||
nsIContent* aRelatedTarget)
|
||||
{
|
||||
if (!aCurrentTarget || !aRelatedTarget) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Walk up the ancestor node trees of the related target until
|
||||
// we encounter the node tree of the current target in order
|
||||
// to find the adjusted related target. Walking up the tree may
|
||||
// not find a common ancestor node tree if the related target is in
|
||||
// an ancestor tree, but in that case it does not need to be adjusted.
|
||||
ShadowRoot* currentTargetShadow = aCurrentTarget->GetContainingShadow();
|
||||
if (!currentTargetShadow) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIContent* relatedTarget = aCurrentTarget;
|
||||
while (relatedTarget) {
|
||||
ShadowRoot* ancestorShadow = relatedTarget->GetContainingShadow();
|
||||
if (currentTargetShadow == ancestorShadow) {
|
||||
return relatedTarget;
|
||||
}
|
||||
|
||||
// Didn't find the ancestor tree, thus related target does not have to
|
||||
// adjusted.
|
||||
if (!ancestorShadow) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
relatedTarget = ancestorShadow->GetHost();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -221,6 +221,14 @@ public:
|
||||
return mIsMainThreadEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given current target, returns the related target adjusted with
|
||||
* shadow DOM retargeting rules. Returns nullptr if related target
|
||||
* is not adjusted.
|
||||
*/
|
||||
static nsIContent* GetShadowRelatedTarget(nsIContent* aCurrentTarget,
|
||||
nsIContent* aRelatedTarget);
|
||||
|
||||
protected:
|
||||
|
||||
// Internal helper functions
|
||||
|
@ -521,7 +521,8 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->originalTarget);
|
||||
bool isInAnon = (content && content->IsInAnonymousSubtree());
|
||||
bool isInAnon = (content && (content->IsInAnonymousSubtree() ||
|
||||
content->IsInShadowTree()));
|
||||
|
||||
aEvent->mFlags.mIsBeingDispatched = true;
|
||||
|
||||
|
@ -9,10 +9,12 @@
|
||||
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
// Microsoft's API Name hackery sucks
|
||||
#undef CreateEvent
|
||||
|
||||
class nsIContent;
|
||||
class nsIDOMEvent;
|
||||
class nsIScriptGlobalObject;
|
||||
class nsPresContext;
|
||||
@ -193,6 +195,13 @@ public:
|
||||
* which should be used when the event is handled at mParentTarget.
|
||||
*/
|
||||
dom::EventTarget* mEventTargetAtParent;
|
||||
|
||||
/**
|
||||
* An array of destination insertion points that need to be inserted
|
||||
* into the event path of nodes that are distributed by the
|
||||
* web components distribution algorithm.
|
||||
*/
|
||||
nsTArray<nsIContent*> mDestInsertionPoints;
|
||||
};
|
||||
|
||||
class EventChainPostVisitor : public mozilla::EventChainVisitor
|
||||
|
@ -279,6 +279,13 @@ MouseEvent::GetRelatedTarget()
|
||||
|
||||
if (relatedTarget) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(relatedTarget);
|
||||
nsCOMPtr<nsIContent> currentTarget = do_QueryInterface(mEvent->currentTarget);
|
||||
|
||||
nsIContent* shadowRelatedTarget = GetShadowRelatedTarget(currentTarget, content);
|
||||
if (shadowRelatedTarget) {
|
||||
relatedTarget = shadowRelatedTarget;
|
||||
}
|
||||
|
||||
if (content && content->ChromeOnlyAccess() &&
|
||||
!nsContentUtils::CanAccessNativeAnon()) {
|
||||
relatedTarget = do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent());
|
||||
|
@ -16,6 +16,9 @@ support-files =
|
||||
[test_document_register_parser.html]
|
||||
[test_document_register_stack.html]
|
||||
[test_document_shared_registry.html]
|
||||
[test_event_dispatch.html]
|
||||
[test_event_retarget.html]
|
||||
[test_event_stopping.html]
|
||||
[test_template.html]
|
||||
[test_template_xhtml.html]
|
||||
[test_shadowroot.html]
|
||||
|
458
dom/tests/mochitest/webcomponents/test_event_dispatch.html
Normal file
458
dom/tests/mochitest/webcomponents/test_event_dispatch.html
Normal file
@ -0,0 +1,458 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=887541
|
||||
-->
|
||||
<head>
|
||||
<title>Test for event model in web components</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887541">Bug 887541</a>
|
||||
<script>
|
||||
|
||||
var els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(SpecialPowers.Ci.nsIEventListenerService);
|
||||
|
||||
function eventListener(e) {
|
||||
eventChain.push(this);
|
||||
}
|
||||
|
||||
function isEventChain(actual, expected, msg) {
|
||||
is(actual.length, expected.length, msg);
|
||||
for (var i = 0; i < expected.length; i++) {
|
||||
is(actual[i], expected[i], msg + " at " + i);
|
||||
}
|
||||
|
||||
// Check to make sure the event chain matches what we get back from nsIEventListenerService.getEventTargetChainFor
|
||||
if (0 < actual.length) {
|
||||
var chain = els.getEventTargetChainFor(actual[0]); // Events should be dispatched on actual[0].
|
||||
for (var i = 0; i < expected.length; i++) {
|
||||
ok(SpecialPowers.compare(chain[i], expected[i]), msg + " at " + i + " for nsIEventListenerService");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test 1: Test of event dispatch through a basic ShadowRoot with content a insertion point.
|
||||
*
|
||||
* <div elemOne> ------ <shadow-root shadowOne>
|
||||
* | |
|
||||
* <div elemTwo> <span elemThree>
|
||||
* |
|
||||
* <content elemFour>
|
||||
*/
|
||||
|
||||
var elemOne = document.createElement("div");
|
||||
elemOne.addEventListener("custom", eventListener);
|
||||
|
||||
var elemTwo = document.createElement("div");
|
||||
elemTwo.addEventListener("custom", eventListener);
|
||||
|
||||
var elemThree = document.createElement("span");
|
||||
elemThree.addEventListener("custom", eventListener);
|
||||
|
||||
var elemFour = document.createElement("content");
|
||||
elemFour.addEventListener("custom", eventListener);
|
||||
|
||||
var shadowOne = elemOne.createShadowRoot();
|
||||
shadowOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemThree.appendChild(elemFour);
|
||||
shadowOne.appendChild(elemThree);
|
||||
elemOne.appendChild(elemTwo);
|
||||
|
||||
var eventChain = [];
|
||||
var customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemTwo.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemTwo, elemFour, elemThree, shadowOne, elemOne], "Event path for test 1 for event dispatched on elemTwo.");
|
||||
|
||||
/*
|
||||
* Test 2: Test of event dispatch through a nested ShadowRoots with content insertion points.
|
||||
*
|
||||
* <div elemFive> --- <shadow-root shadowTwo>
|
||||
* | |
|
||||
* <div elemOne> <div elemFour> ----- <shadow-root shadowOne>
|
||||
* | |
|
||||
* <content elemTwo> <p elemSix>
|
||||
* |
|
||||
* <content elemThree>
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemTwo = document.createElement("content");
|
||||
elemTwo.addEventListener("custom", eventListener);
|
||||
|
||||
elemThree = document.createElement("content");
|
||||
elemThree.addEventListener("custom", eventListener);
|
||||
|
||||
var elemFour = document.createElement("div");
|
||||
elemFour.addEventListener("custom", eventListener);
|
||||
|
||||
var elemFive = document.createElement("div");
|
||||
elemFive.addEventListener("custom", eventListener);
|
||||
|
||||
var elemSix = document.createElement("p");
|
||||
elemSix.addEventListener("custom", eventListener);
|
||||
|
||||
var shadowOne = elemFour.createShadowRoot();
|
||||
shadowOne.addEventListener("custom", eventListener);
|
||||
|
||||
var shadowTwo = elemFive.createShadowRoot();
|
||||
shadowTwo.addEventListener("custom", eventListener);
|
||||
|
||||
elemFive.appendChild(elemOne);
|
||||
shadowTwo.appendChild(elemFour);
|
||||
elemFour.appendChild(elemTwo);
|
||||
shadowOne.appendChild(elemSix);
|
||||
elemSix.appendChild(elemThree);
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemOne.dispatchEvent(customEvent);
|
||||
is(elemOne.getDestinationInsertionPoints().length, 2, "yes");
|
||||
isEventChain(eventChain, [elemOne, elemThree, elemSix, shadowOne, elemTwo, elemFour, shadowTwo, elemFive], "Event path for test 2 for event dispatched on elemOne.");
|
||||
|
||||
/*
|
||||
* Test 3: Test of event dispatch through nested ShadowRoot with content insertion points.
|
||||
*
|
||||
* <div elemOne> ------- <shadow-root shadowOne>
|
||||
* | |
|
||||
* <span elemTwo> <span elemThree> ------------ <shadow-root shadowTwo>
|
||||
* | |
|
||||
* <span elemFour> <content elemSix>
|
||||
* |
|
||||
* <content elemFive>
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemTwo = document.createElement("span");
|
||||
elemTwo.addEventListener("custom", eventListener);
|
||||
|
||||
elemThree = document.createElement("span");
|
||||
elemThree.addEventListener("custom", eventListener);
|
||||
|
||||
elemFour = document.createElement("span");
|
||||
elemFour.addEventListener("custom", eventListener);
|
||||
|
||||
elemFive = document.createElement("content");
|
||||
elemFive.addEventListener("custom", eventListener);
|
||||
|
||||
elemSix = document.createElement("content");
|
||||
elemSix.addEventListener("custom", eventListener);
|
||||
|
||||
shadowOne = elemOne.createShadowRoot();
|
||||
shadowOne.addEventListener("custom", eventListener);
|
||||
|
||||
shadowTwo = elemThree.createShadowRoot();
|
||||
shadowTwo.addEventListener("custom", eventListener);
|
||||
|
||||
elemOne.appendChild(elemTwo);
|
||||
shadowOne.appendChild(elemThree);
|
||||
elemThree.appendChild(elemFour);
|
||||
elemFour.appendChild(elemFive);
|
||||
shadowTwo.appendChild(elemSix);
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemTwo.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemTwo, elemFive, elemFour, elemSix, shadowTwo, elemThree, shadowOne, elemOne], "Event path for test 3 for event dispatched on elemTwo.");
|
||||
|
||||
/*
|
||||
* Test 4: Test of event dispatch through host with multiple ShadowRoots with shadow insertion point.
|
||||
*
|
||||
* <div elemSeven> --- <shadow-root shadowTwo> (younger ShadowRoot)
|
||||
* | | |
|
||||
* <div elemOne> | <div elemSix> -------- <shadow-root shadowOne>
|
||||
* | | |
|
||||
* | <shadow elemFour> <content elemFive>
|
||||
* | |
|
||||
* | <content elemTwo>
|
||||
* |
|
||||
* --- <shadow-root shadowThree> (older ShadowRoot)
|
||||
* | |
|
||||
* | <content elemThree>
|
||||
* |
|
||||
* <div elemEight>
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemTwo = document.createElement("content");
|
||||
elemTwo.addEventListener("custom", eventListener);
|
||||
|
||||
elemThree = document.createElement("content");
|
||||
elemThree.addEventListener("custom", eventListener);
|
||||
|
||||
elemFour = document.createElement("shadow");
|
||||
elemFour.addEventListener("custom", eventListener);
|
||||
|
||||
elemFive = document.createElement("content");
|
||||
elemFive.addEventListener("custom", eventListener);
|
||||
|
||||
elemSix = document.createElement("div");
|
||||
elemSix.addEventListener("custom", eventListener);
|
||||
|
||||
var elemSeven = document.createElement("div");
|
||||
elemSeven.addEventListener("custom", eventListener);
|
||||
|
||||
var elemEight = document.createElement("div");
|
||||
elemEight.addEventListener("custom", eventListener);
|
||||
|
||||
var shadowThree = elemSeven.createShadowRoot();
|
||||
shadowThree.addEventListener("custom", eventListener);
|
||||
|
||||
shadowTwo = elemSeven.createShadowRoot();
|
||||
shadowTwo.addEventListener("custom", eventListener);
|
||||
|
||||
shadowOne = elemSix.createShadowRoot();
|
||||
shadowOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemSeven.appendChild(elemOne);
|
||||
shadowTwo.appendChild(elemSix);
|
||||
elemSix.appendChild(elemFour);
|
||||
elemFour.appendChild(elemTwo);
|
||||
shadowThree.appendChild(elemEight);
|
||||
shadowThree.appendChild(elemThree);
|
||||
shadowOne.appendChild(elemFive);
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemOne.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemOne, elemFive, shadowOne, elemThree, shadowThree, elemTwo, elemFour, elemSix, shadowTwo, elemSeven], "Event path for test 4 for event dispatched on elemOne.");
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemEight.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemEight, elemFive, shadowOne, elemSix, shadowTwo, elemSeven], "Event path for test 4 for event dispatched on elemEight.");
|
||||
|
||||
/*
|
||||
* Test 5: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
|
||||
*
|
||||
* <div elemOne> --------- <shadow-root shadowOne>
|
||||
* | | |
|
||||
* | <p elemThree> <span elemFour> ------------------------ <shadow-root shadowTwo>
|
||||
* | | | |
|
||||
* <span elemTwo> | <content select="p" elemFive> <content elemSeven>
|
||||
* |
|
||||
* <content select="span" elemSix>
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemTwo = document.createElement("span");
|
||||
elemTwo.addEventListener("custom", eventListener);
|
||||
|
||||
elemThree = document.createElement("p");
|
||||
elemThree.addEventListener("custom", eventListener);
|
||||
|
||||
elemFour = document.createElement("span");
|
||||
elemFour.addEventListener("custom", eventListener);
|
||||
|
||||
elemFive = document.createElement("content");
|
||||
elemFive.select = "p";
|
||||
elemFive.addEventListener("custom", eventListener);
|
||||
|
||||
elemSix = document.createElement("content");
|
||||
elemSix.select = "span";
|
||||
elemSix.addEventListener("custom", eventListener);
|
||||
|
||||
elemSeven = document.createElement("content");
|
||||
elemSeven.addEventListener("custom", eventListener);
|
||||
|
||||
shadowTwo = elemFour.createShadowRoot();
|
||||
shadowTwo.addEventListener("custom", eventListener);
|
||||
|
||||
shadowOne = elemOne.createShadowRoot();
|
||||
shadowOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemOne.appendChild(elemTwo);
|
||||
elemOne.appendChild(elemThree);
|
||||
shadowOne.appendChild(elemFour);
|
||||
elemFour.appendChild(elemSix);
|
||||
elemFour.appendChild(elemFive);
|
||||
shadowTwo.appendChild(elemSeven);
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemTwo.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemTwo, elemSeven, shadowTwo, elemSix, elemFour, shadowOne, elemOne], "Event path for test 5 for event dispatched on elemTwo.");
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemSeven, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 5 for event dispatched on elemThree.");
|
||||
|
||||
/*
|
||||
* Test 6: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
|
||||
*
|
||||
* <div elemOne> --------- <shadow-root shadowOne>;
|
||||
* | | |
|
||||
* | <p elemThree> <span elemFour> ------ <shadow-root shadowTwo>
|
||||
* | | | |
|
||||
* <span elemTwo> <content elemFive> | <content select="p" elemSeven>
|
||||
* |
|
||||
* <content select="span" elemSix>
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemTwo = document.createElement("span");
|
||||
elemTwo.addEventListener("custom", eventListener);
|
||||
|
||||
elemThree = document.createElement("p");
|
||||
elemThree.addEventListener("custom", eventListener);
|
||||
|
||||
elemFour = document.createElement("span");
|
||||
elemFour.addEventListener("custom", eventListener);
|
||||
|
||||
elemFive = document.createElement("content");
|
||||
elemFive.addEventListener("custom", eventListener);
|
||||
|
||||
elemSix = document.createElement("content");
|
||||
elemSix.select = "span";
|
||||
elemSix.addEventListener("custom", eventListener);
|
||||
|
||||
elemSeven = document.createElement("content");
|
||||
elemSeven.select = "p";
|
||||
elemSeven.addEventListener("custom", eventListener);
|
||||
|
||||
shadowTwo = elemFour.createShadowRoot();
|
||||
shadowTwo.addEventListener("custom", eventListener);
|
||||
|
||||
shadowOne = elemOne.createShadowRoot();
|
||||
shadowOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemOne.appendChild(elemTwo);
|
||||
elemOne.appendChild(elemThree);
|
||||
shadowOne.appendChild(elemFour);
|
||||
elemFour.appendChild(elemFive);
|
||||
shadowTwo.appendChild(elemSix);
|
||||
shadowTwo.appendChild(elemSeven);
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemTwo.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemTwo, elemSix, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 6 for event dispatched on elemTwo.");
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemSeven, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 6 for event dispatched on elemThree.");
|
||||
|
||||
/*
|
||||
* Test 7: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
|
||||
*
|
||||
* <div elemOne> --------- <shadow-root shadowOne>
|
||||
* | | |
|
||||
* | <p elemThree> <span elemFour> ------ <shadow-root shadowTwo>
|
||||
* | | |
|
||||
* <span elemTwo> <content elemFive> <span elemEight>
|
||||
* | |
|
||||
* | <content select="p" elemSeven>
|
||||
* |
|
||||
* <content select="span" elemSix>
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemTwo = document.createElement("span");
|
||||
elemTwo.addEventListener("custom", eventListener);
|
||||
|
||||
elemThree = document.createElement("p");
|
||||
elemThree.addEventListener("custom", eventListener);
|
||||
|
||||
elemFour = document.createElement("span");
|
||||
elemFour.addEventListener("custom", eventListener);
|
||||
|
||||
elemFive = document.createElement("content");
|
||||
elemFive.addEventListener("custom", eventListener);
|
||||
|
||||
elemSix = document.createElement("content");
|
||||
elemSix.select = "span";
|
||||
elemSix.addEventListener("custom", eventListener);
|
||||
|
||||
elemSeven = document.createElement("content");
|
||||
elemSeven.select = "p";
|
||||
elemSeven.addEventListener("custom", eventListener);
|
||||
|
||||
elemEight = document.createElement("span");
|
||||
elemEight.addEventListener("custom", eventListener);
|
||||
|
||||
shadowTwo = elemFour.createShadowRoot();
|
||||
shadowTwo.addEventListener("custom", eventListener);
|
||||
|
||||
shadowOne = elemOne.createShadowRoot();
|
||||
shadowOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemOne.appendChild(elemTwo);
|
||||
elemOne.appendChild(elemThree);
|
||||
shadowOne.appendChild(elemFour);
|
||||
elemFour.appendChild(elemFive);
|
||||
shadowTwo.appendChild(elemEight);
|
||||
elemEight.appendChild(elemSix);
|
||||
elemEight.appendChild(elemSeven);
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemTwo.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemTwo, elemSix, elemEight, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 7 for event dispatched on elemTwo.");
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemSeven, elemEight, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 7 for event dispatched on elemThree.");
|
||||
|
||||
/*
|
||||
* Test 8: Test of event dispatch through host with multiple ShadowRoots with shadow insertion point.
|
||||
*
|
||||
* <div elemOne> --- <shadow-root shadowOne> (younger ShadowRoot)
|
||||
* | |
|
||||
* | <div elemFour>
|
||||
* | |
|
||||
* | <shadow elemTwo>
|
||||
* |
|
||||
* --- <shadow-root shadowTwo> (older ShadowRoot)
|
||||
* |
|
||||
* <div elemThree>
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemOne.addEventListener("custom", eventListener);
|
||||
|
||||
elemTwo = document.createElement("shadow");
|
||||
elemTwo.addEventListener("custom", eventListener);
|
||||
|
||||
elemThree = document.createElement("div");
|
||||
elemThree.addEventListener("custom", eventListener);
|
||||
|
||||
elemFour = document.createElement("div");
|
||||
elemFour.addEventListener("custom", eventListener);
|
||||
|
||||
shadowTwo = elemOne.createShadowRoot();
|
||||
shadowTwo.addEventListener("custom", eventListener);
|
||||
|
||||
shadowOne = elemOne.createShadowRoot();
|
||||
shadowOne.addEventListener("custom", eventListener);
|
||||
|
||||
shadowOne.appendChild(elemFour);
|
||||
elemFour.appendChild(elemTwo);
|
||||
shadowTwo.appendChild(elemThree);
|
||||
|
||||
eventChain = [];
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, shadowTwo, elemTwo, elemFour, shadowOne, elemOne], "Event path for test 8 for event dispatched on elemThree.");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
147
dom/tests/mochitest/webcomponents/test_event_retarget.html
Normal file
147
dom/tests/mochitest/webcomponents/test_event_retarget.html
Normal file
@ -0,0 +1,147 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=887541
|
||||
-->
|
||||
<head>
|
||||
<title>Test for event retargeting in web components</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887541">Bug 887541</a>
|
||||
<script>
|
||||
|
||||
/*
|
||||
* Creates an event listener with an expected event target.
|
||||
*/
|
||||
function createEventListener(expectedTarget, msg) {
|
||||
return function(e) {
|
||||
is(e.target, expectedTarget, msg);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Test of event retargeting through a basic ShadowRoot with a content insertion point.
|
||||
*
|
||||
* <div elemThree> ---- <shadow-root shadowOne>
|
||||
* | |
|
||||
* <div elemOne> <content elemTwo>
|
||||
*
|
||||
* Dispatch event on elemOne
|
||||
*/
|
||||
|
||||
var elemOne = document.createElement("div");
|
||||
var elemTwo = document.createElement("content");
|
||||
var elemThree = document.createElement("div");
|
||||
var shadowOne = elemThree.createShadowRoot();
|
||||
|
||||
elemThree.appendChild(elemOne);
|
||||
shadowOne.appendChild(elemTwo);
|
||||
|
||||
elemOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemOne."));
|
||||
elemTwo.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemTwo."));
|
||||
elemThree.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemThree."));
|
||||
shadowOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of shadowOne."));
|
||||
|
||||
var customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemOne.dispatchEvent(customEvent);
|
||||
|
||||
/*
|
||||
* Test of event retargeting through a basic ShadowRoot with a content insertion point.
|
||||
*
|
||||
* <div elemThree> ---- <shadow-root shadowOne>
|
||||
* | |
|
||||
* <div elemOne> <content elemTwo>
|
||||
*
|
||||
* Dispatch event on elemTwo
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemTwo = document.createElement("content");
|
||||
elemThree = document.createElement("div");
|
||||
shadowOne = elemThree.createShadowRoot();
|
||||
|
||||
elemThree.appendChild(elemOne);
|
||||
shadowOne.appendChild(elemTwo);
|
||||
|
||||
elemTwo.addEventListener("custom", createEventListener(elemTwo, "elemTwo is in common ancestor tree of elemTwo."));
|
||||
elemThree.addEventListener("custom", createEventListener(elemThree, "elemThree is in common ancestor tree of elemThree."));
|
||||
shadowOne.addEventListener("custom", createEventListener(elemTwo, "elemTwo is in common ancestor tree of shadowOne."));
|
||||
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemTwo.dispatchEvent(customEvent);
|
||||
|
||||
/*
|
||||
* Test of event retargeting through a nested ShadowRoots with content insertion points.
|
||||
*
|
||||
* <div elemFive> --- <shadow-root shadowTwo>
|
||||
* | |
|
||||
* <div elemOne> <div elemFour> ----- <shadow-root shadowOne>
|
||||
* | |
|
||||
* <content elemTwo> <content elemThree>
|
||||
*
|
||||
* Dispatch custom event on elemOne.
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemTwo = document.createElement("content");
|
||||
elemThree = document.createElement("content");
|
||||
var elemFour = document.createElement("div");
|
||||
var elemFive = document.createElement("div");
|
||||
var shadowTwo = elemFive.createShadowRoot();
|
||||
shadowOne = elemFour.createShadowRoot();
|
||||
|
||||
elemFive.appendChild(elemOne);
|
||||
shadowTwo.appendChild(elemFour);
|
||||
elemFour.appendChild(elemTwo);
|
||||
shadowOne.appendChild(elemThree);
|
||||
|
||||
elemOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemOne."));
|
||||
elemTwo.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemTwo."));
|
||||
elemThree.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemThree."));
|
||||
elemFour.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemFour."));
|
||||
elemFive.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemFive."));
|
||||
shadowOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of shadowOne."));
|
||||
shadowTwo.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of shadowTwo."));
|
||||
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemOne.dispatchEvent(customEvent);
|
||||
|
||||
/*
|
||||
* Test of event retargeting through a nested ShadowRoots with content insertion points.
|
||||
*
|
||||
* <div elemFive> --- <shadow-root shadowTwo>
|
||||
* | |
|
||||
* <div elemOne> <div elemFour> ----- <shadow-root shadowOne>
|
||||
* | |
|
||||
* <content elemTwo> <content elemThree>
|
||||
*
|
||||
* Dispatch custom event on elemThree.
|
||||
*/
|
||||
|
||||
elemOne = document.createElement("div");
|
||||
elemTwo = document.createElement("content");
|
||||
elemThree = document.createElement("content");
|
||||
elemFour = document.createElement("div");
|
||||
elemFive = document.createElement("div");
|
||||
shadowTwo = elemFive.createShadowRoot();
|
||||
shadowOne = elemFour.createShadowRoot();
|
||||
|
||||
elemFive.appendChild(elemOne);
|
||||
shadowTwo.appendChild(elemFour);
|
||||
elemFour.appendChild(elemTwo);
|
||||
shadowOne.appendChild(elemThree);
|
||||
|
||||
elemThree.addEventListener("custom", createEventListener(elemThree, "elemThree is in common ancestor tree of elemThree."));
|
||||
elemFour.addEventListener("custom", createEventListener(elemFour, "elemFour is in common ancestor tree of elemFour."));
|
||||
elemFive.addEventListener("custom", createEventListener(elemFive, "elemFive is in common ancestor tree of elemFive."));
|
||||
shadowOne.addEventListener("custom", createEventListener(elemThree, "elemThree is in common ancestor tree of shadowOne."));
|
||||
shadowTwo.addEventListener("custom", createEventListener(elemFour, "elemFour is in common ancestor tree of shadowTwo."));
|
||||
|
||||
customEvent = new CustomEvent("custom", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
168
dom/tests/mochitest/webcomponents/test_event_stopping.html
Normal file
168
dom/tests/mochitest/webcomponents/test_event_stopping.html
Normal file
@ -0,0 +1,168 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=887541
|
||||
-->
|
||||
<head>
|
||||
<title>Test for event model in web components</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887541">Bug 887541</a>
|
||||
<script>
|
||||
|
||||
var els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(SpecialPowers.Ci.nsIEventListenerService);
|
||||
|
||||
function eventListener(e) {
|
||||
eventChain.push(this);
|
||||
}
|
||||
|
||||
function isEventChain(actual, expected, msg) {
|
||||
is(actual.length, expected.length, msg);
|
||||
for (var i = 0; i < expected.length; i++) {
|
||||
is(actual[i], expected[i], msg + " at " + i);
|
||||
}
|
||||
|
||||
if (0 < actual.length) {
|
||||
var chain = els.getEventTargetChainFor(actual[0]); // Events should be dispatched on actual[0].
|
||||
ok(expected.length < chain.length, "There should be additional chrome event targets.");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* <div elemOne> ------ <shadow-root shadowOne>
|
||||
* |
|
||||
* <span elemTwo>
|
||||
* |
|
||||
* <span elemThree>
|
||||
*/
|
||||
|
||||
var elemOne = document.createElement("div");
|
||||
var elemTwo = document.createElement("span");
|
||||
var elemThree = document.createElement("span");
|
||||
var shadowOne = elemOne.createShadowRoot();
|
||||
|
||||
shadowOne.appendChild(elemTwo);
|
||||
elemTwo.appendChild(elemThree);
|
||||
|
||||
// Test stopping "abort" event.
|
||||
|
||||
elemOne.addEventListener("abort", eventListener);
|
||||
elemTwo.addEventListener("abort", eventListener);
|
||||
elemThree.addEventListener("abort", eventListener);
|
||||
shadowOne.addEventListener("abort", eventListener);
|
||||
|
||||
var eventChain = [];
|
||||
|
||||
var customEvent = new CustomEvent("abort", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that abort event is stopped at shadow root.");
|
||||
|
||||
// Test stopping "error" event.
|
||||
|
||||
elemOne.addEventListener("error", eventListener);
|
||||
elemTwo.addEventListener("error", eventListener);
|
||||
elemThree.addEventListener("error", eventListener);
|
||||
shadowOne.addEventListener("error", eventListener);
|
||||
|
||||
eventChain = [];
|
||||
|
||||
customEvent = new CustomEvent("error", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that error event is stopped at shadow root.");
|
||||
|
||||
// Test stopping "select" event.
|
||||
|
||||
elemOne.addEventListener("select", eventListener);
|
||||
elemTwo.addEventListener("select", eventListener);
|
||||
elemThree.addEventListener("select", eventListener);
|
||||
shadowOne.addEventListener("select", eventListener);
|
||||
|
||||
eventChain = [];
|
||||
|
||||
customEvent = new CustomEvent("select", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that select event is stopped at shadow root.");
|
||||
|
||||
// Test stopping "change" event.
|
||||
|
||||
elemOne.addEventListener("change", eventListener);
|
||||
elemTwo.addEventListener("change", eventListener);
|
||||
elemThree.addEventListener("change", eventListener);
|
||||
shadowOne.addEventListener("change", eventListener);
|
||||
|
||||
eventChain = [];
|
||||
|
||||
customEvent = new CustomEvent("change", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
|
||||
// Test stopping "reset" event.
|
||||
|
||||
elemOne.addEventListener("reset", eventListener);
|
||||
elemTwo.addEventListener("reset", eventListener);
|
||||
elemThree.addEventListener("reset", eventListener);
|
||||
shadowOne.addEventListener("reset", eventListener);
|
||||
|
||||
eventChain = [];
|
||||
|
||||
customEvent = new CustomEvent("reset", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that reset event is stopped at shadow root.");
|
||||
|
||||
// Test stopping "load" event.
|
||||
|
||||
elemOne.addEventListener("load", eventListener);
|
||||
elemTwo.addEventListener("load", eventListener);
|
||||
elemThree.addEventListener("load", eventListener);
|
||||
shadowOne.addEventListener("load", eventListener);
|
||||
|
||||
eventChain = [];
|
||||
|
||||
customEvent = new CustomEvent("load", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that load event is stopped at shadow root.");
|
||||
|
||||
// Test stopping "resize" event.
|
||||
|
||||
elemOne.addEventListener("resize", eventListener);
|
||||
elemTwo.addEventListener("resize", eventListener);
|
||||
elemThree.addEventListener("resize", eventListener);
|
||||
shadowOne.addEventListener("resize", eventListener);
|
||||
|
||||
eventChain = [];
|
||||
|
||||
customEvent = new CustomEvent("resize", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that resize event is stopped at shadow root.");
|
||||
|
||||
// Test stopping "scroll" event.
|
||||
|
||||
elemOne.addEventListener("scroll", eventListener);
|
||||
elemTwo.addEventListener("scroll", eventListener);
|
||||
elemThree.addEventListener("scroll", eventListener);
|
||||
shadowOne.addEventListener("scroll", eventListener);
|
||||
|
||||
eventChain = [];
|
||||
|
||||
customEvent = new CustomEvent("scroll", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that scroll event is stopped at shadow root.");
|
||||
|
||||
// Test stopping "selectstart" event.
|
||||
|
||||
elemOne.addEventListener("selectstart", eventListener);
|
||||
elemTwo.addEventListener("selectstart", eventListener);
|
||||
elemThree.addEventListener("selectstart", eventListener);
|
||||
shadowOne.addEventListener("selectstart", eventListener);
|
||||
|
||||
eventChain = [];
|
||||
|
||||
customEvent = new CustomEvent("selectstart", { "bubbles" : true });
|
||||
elemThree.dispatchEvent(customEvent);
|
||||
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that selectstart event is stopped at shadow root.");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user