mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-03 22:38:41 +09:00
Bug 1409975 - Implement node distribution for shadow tree slots
* Implementation for assignedNodes * Include slots in the flat tree * Fix event get-the-parent algorithm for a node * Update and add reftests for Shadow DOM v1 * Update web platform tests expectations Tag #1375
This commit is contained in:
parent
a7ba34c672
commit
cab78760e5
49 changed files with 775 additions and 429 deletions
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "ChildIterator.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/XBLChildrenElement.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
|
|
@ -57,15 +58,34 @@ GetMatchedNodesForPoint(nsIContent* aContent)
|
|||
// XXX handle <slot> element?
|
||||
}
|
||||
|
||||
ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning)
|
||||
: mParent(aParent),
|
||||
mChild(nullptr),
|
||||
mDefaultChild(nullptr),
|
||||
mIsFirst(aStartAtBeginning),
|
||||
mIndexInInserted(0)
|
||||
{
|
||||
mParentAsSlot = HTMLSlotElement::FromContent(mParent);
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
ExplicitChildIterator::GetNextChild()
|
||||
{
|
||||
// If we're already in the inserted-children array, look there first
|
||||
if (mIndexInInserted) {
|
||||
MOZ_ASSERT(mChild);
|
||||
MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
|
||||
MOZ_ASSERT(!mDefaultChild);
|
||||
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
|
||||
mChild = (mIndexInInserted < assignedNodes.Length()) ?
|
||||
assignedNodes[mIndexInInserted++]->AsContent() : nullptr;
|
||||
return mChild;
|
||||
}
|
||||
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
if (mIndexInInserted < assignedChildren.Length()) {
|
||||
return assignedChildren[mIndexInInserted++];
|
||||
|
|
@ -84,6 +104,19 @@ ExplicitChildIterator::GetNextChild()
|
|||
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (mIsFirst) { // at the beginning of the child list
|
||||
// For slot parent, iterate over assigned nodes if not empty, otherwise
|
||||
// fall through and iterate over direct children (fallback content).
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
if (!assignedNodes.IsEmpty()) {
|
||||
mIndexInInserted = 1;
|
||||
mChild = assignedNodes[0]->AsContent();
|
||||
mIsFirst = false;
|
||||
return mChild;
|
||||
}
|
||||
}
|
||||
|
||||
mChild = mParent->GetFirstChild();
|
||||
mIsFirst = false;
|
||||
} else if (mChild) { // in the middle of the child list
|
||||
|
|
@ -185,6 +218,12 @@ ExplicitChildIterator::Get() const
|
|||
{
|
||||
MOZ_ASSERT(!mIsFirst);
|
||||
|
||||
// When mParentAsSlot is set, mChild is always set to the current child. It
|
||||
// does not matter whether mChild is an assigned node or a fallback content.
|
||||
if (mParentAsSlot) {
|
||||
return mChild;
|
||||
}
|
||||
|
||||
if (mIndexInInserted) {
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
return assignedChildren[mIndexInInserted - 1];
|
||||
|
|
@ -198,6 +237,20 @@ ExplicitChildIterator::GetPreviousChild()
|
|||
{
|
||||
// If we're already in the inserted-children array, look there first
|
||||
if (mIndexInInserted) {
|
||||
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
|
||||
mChild = (--mIndexInInserted) ?
|
||||
assignedNodes[mIndexInInserted - 1]->AsContent() : nullptr;
|
||||
|
||||
if (!mChild) {
|
||||
mIsFirst = true;
|
||||
}
|
||||
return mChild;
|
||||
}
|
||||
|
||||
// NB: mIndexInInserted points one past the last returned child so we need
|
||||
// to look *two* indices back in order to return the previous child.
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
|
|
@ -218,6 +271,18 @@ ExplicitChildIterator::GetPreviousChild()
|
|||
} else if (mChild) { // in the middle of the child list
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else { // at the end of the child list
|
||||
// For slot parent, iterate over assigned nodes if not empty, otherwise
|
||||
// fall through and iterate over direct children (fallback content).
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
if (!assignedNodes.IsEmpty()) {
|
||||
mIndexInInserted = assignedNodes.Length();
|
||||
mChild = assignedNodes[mIndexInInserted - 1]->AsContent();
|
||||
return mChild;
|
||||
}
|
||||
}
|
||||
|
||||
mChild = mParent->GetLastChild();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,22 +36,19 @@ class ExplicitChildIterator
|
|||
{
|
||||
public:
|
||||
explicit ExplicitChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning = true)
|
||||
: mParent(aParent),
|
||||
mChild(nullptr),
|
||||
mDefaultChild(nullptr),
|
||||
mIndexInInserted(0),
|
||||
mIsFirst(aStartAtBeginning)
|
||||
{
|
||||
}
|
||||
bool aStartAtBeginning = true);
|
||||
|
||||
ExplicitChildIterator(const ExplicitChildIterator& aOther)
|
||||
: mParent(aOther.mParent), mChild(aOther.mChild),
|
||||
: mParent(aOther.mParent),
|
||||
mParentAsSlot(aOther.mParentAsSlot),
|
||||
mChild(aOther.mChild),
|
||||
mDefaultChild(aOther.mDefaultChild),
|
||||
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
|
||||
|
||||
ExplicitChildIterator(ExplicitChildIterator&& aOther)
|
||||
: mParent(aOther.mParent), mChild(aOther.mChild),
|
||||
: mParent(aOther.mParent),
|
||||
mParentAsSlot(aOther.mParentAsSlot),
|
||||
mChild(aOther.mChild),
|
||||
mDefaultChild(aOther.mDefaultChild),
|
||||
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
|
||||
|
||||
|
|
@ -98,6 +95,10 @@ protected:
|
|||
// the <xbl:content> element for the binding.
|
||||
const nsIContent* mParent;
|
||||
|
||||
// If parent is a slot element, this points to the parent as HTMLSlotElement,
|
||||
// otherwise, it's null.
|
||||
const HTMLSlotElement* mParentAsSlot;
|
||||
|
||||
// The current child. When we encounter an insertion point,
|
||||
// mChild remains as the insertion point whose content we're iterating (and
|
||||
// our state is controled by mDefaultChild or mIndexInInserted depending on
|
||||
|
|
|
|||
|
|
@ -182,6 +182,24 @@ nsIContent::GetAssignedSlotByMode() const
|
|||
return slot;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
nsIContent::GetFlattenedTreeParentForMaybeAssignedNode() const
|
||||
{
|
||||
if (HTMLSlotElement* assignedSlot = GetAssignedSlot()) {
|
||||
return assignedSlot;
|
||||
}
|
||||
|
||||
HTMLSlotElement* parentSlot = HTMLSlotElement::FromContent(GetParent());
|
||||
if (!parentSlot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If this is not an unassigned node, then it must be a fallback content.
|
||||
MOZ_ASSERT(parentSlot->AssignedNodes().IsEmpty());
|
||||
|
||||
return parentSlot;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
|
||||
{
|
||||
|
|
@ -233,16 +251,10 @@ nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
|
|||
|
||||
if (parent && nsContentUtils::HasDistributedChildren(parent) &&
|
||||
nsContentUtils::IsInSameAnonymousTree(parent, this)) {
|
||||
// This node is distributed to insertion points, thus we
|
||||
// need to consult the destination insertion points list to
|
||||
// figure out where this node was inserted in the flattened tree.
|
||||
// It may be the case that |parent| distributes its children
|
||||
// but the child does not match any insertion points, thus
|
||||
// the flattened tree parent is nullptr.
|
||||
nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
|
||||
parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ?
|
||||
destInsertionPoints->LastElement()->GetParent() : nullptr;
|
||||
} else if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
||||
return GetFlattenedTreeParentForMaybeAssignedNode();
|
||||
}
|
||||
|
||||
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
||||
nsIContent* insertionParent = GetXBLInsertionParent();
|
||||
if (insertionParent) {
|
||||
parent = insertionParent;
|
||||
|
|
@ -890,42 +902,10 @@ nsIContent::GetEventTargetParent(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.
|
||||
for (uint32_t i = 0; i < destPoints->Length(); i++) {
|
||||
nsIContent* point = destPoints->ElementAt(i);
|
||||
aVisitor.mDestInsertionPoints.AppendElement(point);
|
||||
}
|
||||
}
|
||||
|
||||
ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this);
|
||||
if (thisShadowRoot) {
|
||||
if (!aVisitor.mEvent->mFlags.mComposed) {
|
||||
// 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<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
|
||||
EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
|
||||
? 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 {
|
||||
parent = thisShadowRoot->GetHost();
|
||||
}
|
||||
}
|
||||
// Event parent is the assigned slot, if node is assigned, or node's parent
|
||||
// otherwise.
|
||||
HTMLSlotElement* slot = GetAssignedSlot();
|
||||
nsIContent* parent = slot ? slot : GetParent();
|
||||
|
||||
// Event may need to be retargeted if this is the root of a native
|
||||
// anonymous content subtree or event is dispatched somewhere inside XBL.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
|
||||
|
|
@ -109,6 +111,87 @@ ShadowRoot::FromNode(nsINode* aNode)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::AddSlot(HTMLSlotElement* aSlot)
|
||||
{
|
||||
MOZ_ASSERT(aSlot);
|
||||
|
||||
// Note that if name attribute missing, the slot is a default slot.
|
||||
nsAutoString name;
|
||||
aSlot->GetName(name);
|
||||
|
||||
nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.LookupOrAdd(name);
|
||||
MOZ_ASSERT(currentSlots);
|
||||
|
||||
HTMLSlotElement* oldSlot = currentSlots->IsEmpty() ?
|
||||
nullptr : currentSlots->ElementAt(0);
|
||||
|
||||
TreeOrderComparator comparator;
|
||||
currentSlots->InsertElementSorted(aSlot, comparator);
|
||||
|
||||
HTMLSlotElement* currentSlot = currentSlots->ElementAt(0);
|
||||
if (currentSlot != aSlot) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldSlot && oldSlot != currentSlot) {
|
||||
// Move assigned nodes from old slot to new slot.
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
|
||||
while (assignedNodes.Length() > 0) {
|
||||
nsINode* assignedNode = assignedNodes[0];
|
||||
|
||||
oldSlot->RemoveAssignedNode(assignedNode);
|
||||
currentSlot->AppendAssignedNode(assignedNode);
|
||||
}
|
||||
} else {
|
||||
// Otherwise add appropriate nodes to this slot from the host.
|
||||
for (nsIContent* child = GetHost()->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
nsAutoString slotName;
|
||||
child->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
if (child->IsSlotable() && slotName.Equals(name)) {
|
||||
currentSlot->AppendAssignedNode(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot)
|
||||
{
|
||||
MOZ_ASSERT(aSlot);
|
||||
|
||||
nsAutoString name;
|
||||
aSlot->GetName(name);
|
||||
|
||||
nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.Get(name);
|
||||
|
||||
if (currentSlots) {
|
||||
if (currentSlots->Length() == 1) {
|
||||
MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
|
||||
mSlotMap.Remove(name);
|
||||
aSlot->ClearAssignedNodes();
|
||||
} else {
|
||||
bool doReplaceSlot = currentSlots->ElementAt(0) == aSlot;
|
||||
currentSlots->RemoveElement(aSlot);
|
||||
HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
|
||||
|
||||
// Move assigned nodes from removed slot to the next slot in
|
||||
// tree order with the same name.
|
||||
if (doReplaceSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
|
||||
while (assignedNodes.Length() > 0) {
|
||||
nsINode* assignedNode = assignedNodes[0];
|
||||
|
||||
aSlot->RemoveAssignedNode(assignedNode);
|
||||
replacementSlot->AppendAssignedNode(assignedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::StyleSheetChanged()
|
||||
{
|
||||
|
|
@ -222,6 +305,128 @@ ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
|
|||
return nsContentUtils::GetElementsByClassName(this, aClasses);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
|
||||
// https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
|
||||
if (!aVisitor.mEvent->mFlags.mComposed) {
|
||||
nsCOMPtr<nsIContent> originalTarget =
|
||||
do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
|
||||
if (originalTarget->GetContainingShadow() == this) {
|
||||
// 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<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
|
||||
EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
|
||||
? win->GetParentTarget() : nullptr;
|
||||
|
||||
aVisitor.mParentTarget = parentTarget;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsIContent* shadowHost = GetHost();
|
||||
aVisitor.mParentTarget = shadowHost;
|
||||
|
||||
if (aVisitor.mOriginalTargetIsInAnon) {
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
|
||||
if (content && content->GetBindingParent() == shadowHost) {
|
||||
aVisitor.mEventTargetAtParent = shadowHost;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const HTMLSlotElement*
|
||||
ShadowRoot::AssignSlotFor(nsIContent* aContent)
|
||||
{
|
||||
nsAutoString slotName;
|
||||
// Note that if slot attribute is missing, assign it to the first default
|
||||
// slot, if exists.
|
||||
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(slotName);
|
||||
if (!slots) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HTMLSlotElement* slot = slots->ElementAt(0);
|
||||
MOZ_ASSERT(slot);
|
||||
|
||||
// Find the appropriate position in the assigned node list for the
|
||||
// newly assigned content.
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
||||
nsIContent* currentContent = GetHost()->GetFirstChild();
|
||||
bool indexFound = false;
|
||||
uint32_t insertionIndex;
|
||||
for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
|
||||
// Seek through the host's explicit children until the
|
||||
// assigned content is found.
|
||||
while (currentContent && currentContent != assignedNodes[i]) {
|
||||
if (currentContent == aContent) {
|
||||
indexFound = true;
|
||||
insertionIndex = i;
|
||||
}
|
||||
|
||||
currentContent = currentContent->GetNextSibling();
|
||||
}
|
||||
|
||||
if (indexFound) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (indexFound) {
|
||||
slot->InsertAssignedNode(insertionIndex, aContent);
|
||||
} else {
|
||||
slot->AppendAssignedNode(aContent);
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
const HTMLSlotElement*
|
||||
ShadowRoot::UnassignSlotFor(nsIContent* aNode, const nsAString& aSlotName)
|
||||
{
|
||||
// Find the insertion point to which the content belongs. Note that if slot
|
||||
// attribute is missing, unassign it from the first default slot, if exists.
|
||||
nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(aSlotName);
|
||||
if (!slots) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HTMLSlotElement* slot = slots->ElementAt(0);
|
||||
MOZ_ASSERT(slot);
|
||||
|
||||
if (!slot->AssignedNodes().Contains(aNode)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
slot->RemoveAssignedNode(aNode);
|
||||
return slot;
|
||||
}
|
||||
|
||||
bool
|
||||
ShadowRoot::MaybeReassignElement(Element* aElement,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
nsIContent* parent = aElement->GetParent();
|
||||
if (parent && parent == GetHost()) {
|
||||
const HTMLSlotElement* oldSlot = UnassignSlotFor(aElement,
|
||||
aOldValue ? aOldValue->GetStringValue() : EmptyString());
|
||||
const HTMLSlotElement* newSlot = AssignSlotFor(aElement);
|
||||
|
||||
if (oldSlot != newSlot) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::DistributionChanged()
|
||||
{
|
||||
|
|
@ -333,7 +538,12 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
|
|||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
if (!IsPooledNode(aElement)) {
|
||||
if (aNameSpaceID != kNameSpaceID_None || aAttribute != nsGkAtoms::slot) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attributes may change insertion point matching, find its new distribution.
|
||||
if (!MaybeReassignElement(aElement, aOldValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -369,11 +579,18 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
|
|||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer)
|
||||
{
|
||||
if (mInsertionPointChanged) {
|
||||
DistributeAllNodes();
|
||||
mInsertionPointChanged = false;
|
||||
// Check to ensure that the content is in the same anonymous tree
|
||||
// as the container because anonymous content may report its container
|
||||
// as the host but it may not be in the host's child list.
|
||||
if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aChild->IsSlotable() || aContainer != GetHost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AssignSlotFor(aChild);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -383,11 +600,20 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
|
|||
int32_t aIndexInContainer,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
if (mInsertionPointChanged) {
|
||||
DistributeAllNodes();
|
||||
mInsertionPointChanged = false;
|
||||
// Check to ensure that the content is in the same anonymous tree
|
||||
// as the container because anonymous content may report its container
|
||||
// as the host but it may not be in the host's child list.
|
||||
if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aChild->IsSlotable() || aContainer != GetHost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString slotName;
|
||||
aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
UnassignSlotFor(aChild, slotName);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ class nsIContent;
|
|||
class nsXBLPrototypeBinding;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EventChainPreVisitor;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Element;
|
||||
|
|
@ -73,10 +76,26 @@ public:
|
|||
|
||||
private:
|
||||
/**
|
||||
* Redistributes a node of the pool, and returns whether the distribution
|
||||
* Try to reassign an element to a slot and returns whether the assignment
|
||||
* changed.
|
||||
*/
|
||||
bool RedistributeElement(Element*);
|
||||
bool MaybeReassignElement(Element* aElement, const nsAttrValue* aOldValue);
|
||||
|
||||
/**
|
||||
* Try to assign aContent to a slot in the shadow tree, returns the assigned
|
||||
* slot if found.
|
||||
*/
|
||||
const HTMLSlotElement* AssignSlotFor(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Unassign aContent from the assigned slot in the shadow tree, returns the
|
||||
* assigned slot if found.
|
||||
*
|
||||
* Note: slot attribute of aContent may have changed already, so pass slot
|
||||
* name explicity here.
|
||||
*/
|
||||
const HTMLSlotElement* UnassignSlotFor(nsIContent* aContent,
|
||||
const nsAString& aSlotName);
|
||||
|
||||
/**
|
||||
* Called when we redistribute content after insertion points have changed.
|
||||
|
|
@ -86,6 +105,9 @@ private:
|
|||
bool IsPooledNode(nsIContent* aChild) const;
|
||||
|
||||
public:
|
||||
void AddSlot(HTMLSlotElement* aSlot);
|
||||
void RemoveSlot(HTMLSlotElement* aSlot);
|
||||
|
||||
void SetInsertionPointChanged() { mInsertionPointChanged = true; }
|
||||
|
||||
void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; }
|
||||
|
|
@ -113,11 +135,18 @@ public:
|
|||
mIsComposedDocParticipant = aIsComposedDocParticipant;
|
||||
}
|
||||
|
||||
nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
protected:
|
||||
virtual ~ShadowRoot();
|
||||
|
||||
ShadowRootMode mMode;
|
||||
|
||||
// Map from name of slot to an array of all slots in the shadow DOM with with
|
||||
// the given name. The slots are stored as a weak pointer because the elements
|
||||
// are in the shadow tree and should be kept alive by its parent.
|
||||
nsClassHashtable<nsStringHashKey, nsTArray<mozilla::dom::HTMLSlotElement*>> mSlotMap;
|
||||
|
||||
nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
|
||||
nsXBLPrototypeBinding* mProtoBinding;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/FileSystemSecurity.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
|
|
@ -7053,6 +7054,13 @@ nsContentUtils::HasDistributedChildren(nsIContent* aContent)
|
|||
return true;
|
||||
}
|
||||
|
||||
HTMLSlotElement* slotEl = HTMLSlotElement::FromContent(aContent);
|
||||
if (slotEl && slotEl->GetContainingShadow()) {
|
||||
// Children of a slot are rendered if the slot does not have any assigned
|
||||
// nodes (fallback content).
|
||||
return slotEl->AssignedNodes().IsEmpty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -999,6 +999,12 @@ protected:
|
|||
*/
|
||||
nsIAtom* DoGetID() const;
|
||||
|
||||
/**
|
||||
* Returns the assigned slot, if it exists, or the direct parent, if it's a
|
||||
* fallback content of a slot.
|
||||
*/
|
||||
nsINode* GetFlattenedTreeParentForMaybeAssignedNode() const;
|
||||
|
||||
public:
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -408,6 +408,12 @@ public:
|
|||
*/
|
||||
virtual bool IsNodeOfType(uint32_t aFlags) const = 0;
|
||||
|
||||
bool
|
||||
IsSlotable() const
|
||||
{
|
||||
return IsElement() || IsNodeOfType(eTEXT);
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -204,13 +204,6 @@ 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
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/HTMLSlotElementBinding.h"
|
||||
#include "mozilla/dom/HTMLUnknownElement.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsDocument.h"
|
||||
|
||||
|
|
@ -15,12 +16,10 @@ NS_NewHTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
|||
mozilla::dom::FromParser aFromParser)
|
||||
{
|
||||
RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
|
||||
/* Disabled for now
|
||||
if (nsDocument::IsWebComponentsEnabled(nodeInfo)) {
|
||||
already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
|
||||
return new mozilla::dom::HTMLSlotElement(nodeInfoArg);
|
||||
}
|
||||
*/
|
||||
|
||||
already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
|
||||
return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
|
||||
|
|
@ -50,13 +49,161 @@ NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
|
|||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLSlotElement)
|
||||
|
||||
nsresult
|
||||
HTMLSlotElement::BindToTree(nsIDocument* aDocument,
|
||||
nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
if (containingShadow && !oldContainingShadow) {
|
||||
containingShadow->AddSlot(this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSlotElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
if (oldContainingShadow && !GetContainingShadow()) {
|
||||
oldContainingShadow->RemoveSlot(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLSlotElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::name) {
|
||||
if (ShadowRoot* containingShadow = GetContainingShadow()) {
|
||||
containingShadow->RemoveSlot(this);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLSlotElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
bool aNotify)
|
||||
{
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::name) {
|
||||
if (ShadowRoot* containingShadow = GetContainingShadow()) {
|
||||
containingShadow->AddSlot(this);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
|
||||
aOldValue, aNotify);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten assigned nodes given a slot, as in:
|
||||
* https://dom.spec.whatwg.org/#find-flattened-slotables
|
||||
*/
|
||||
static void
|
||||
FlattenAssignedNodes(HTMLSlotElement* aSlot, nsTArray<RefPtr<nsINode>>& aNodes)
|
||||
{
|
||||
if (!aSlot->GetContainingShadow()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
|
||||
|
||||
// If assignedNodes is empty, use children of slot as fallback content.
|
||||
if (assignedNodes.IsEmpty()) {
|
||||
for (nsIContent* child = aSlot->AsContent()->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (!child->IsSlotable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child->IsHTMLElement(nsGkAtoms::slot)) {
|
||||
FlattenAssignedNodes(HTMLSlotElement::FromContent(child), aNodes);
|
||||
} else {
|
||||
aNodes.AppendElement(child);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
|
||||
nsINode* assignedNode = assignedNodes[i];
|
||||
if (assignedNode->IsHTMLElement(nsGkAtoms::slot)) {
|
||||
FlattenAssignedNodes(
|
||||
HTMLSlotElement::FromContent(assignedNode->AsContent()), aNodes);
|
||||
} else {
|
||||
aNodes.AppendElement(assignedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSlotElement::AssignedNodes(const AssignedNodesOptions& aOptions,
|
||||
nsTArray<RefPtr<nsINode>>& aNodes)
|
||||
{
|
||||
if (aOptions.mFlatten) {
|
||||
return FlattenAssignedNodes(this, aNodes);
|
||||
}
|
||||
|
||||
aNodes = mAssignedNodes;
|
||||
}
|
||||
|
||||
const nsTArray<RefPtr<nsINode>>&
|
||||
HTMLSlotElement::AssignedNodes() const
|
||||
{
|
||||
return mAssignedNodes;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSlotElement::InsertAssignedNode(uint32_t aIndex, nsINode* aNode)
|
||||
{
|
||||
mAssignedNodes.InsertElementAt(aIndex, aNode);
|
||||
aNode->AsContent()->SetAssignedSlot(this);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSlotElement::AppendAssignedNode(nsINode* aNode)
|
||||
{
|
||||
mAssignedNodes.AppendElement(aNode);
|
||||
aNode->AsContent()->SetAssignedSlot(this);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSlotElement::RemoveAssignedNode(nsINode* aNode)
|
||||
{
|
||||
mAssignedNodes.RemoveElement(aNode);
|
||||
aNode->AsContent()->SetAssignedSlot(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSlotElement::ClearAssignedNodes()
|
||||
{
|
||||
for (uint32_t i = 0; i < mAssignedNodes.Length(); i++) {
|
||||
mAssignedNodes[i]->AsContent()->SetAssignedSlot(nullptr);
|
||||
}
|
||||
|
||||
mAssignedNodes.Clear();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLSlotElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,22 @@ public:
|
|||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true) override;
|
||||
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
bool aNotify) override;
|
||||
|
||||
// WebIDL
|
||||
void SetName(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::name, aName, aRv);
|
||||
|
|
@ -39,6 +55,13 @@ public:
|
|||
void AssignedNodes(const AssignedNodesOptions& aOptions,
|
||||
nsTArray<RefPtr<nsINode>>& aNodes);
|
||||
|
||||
// Helper methods
|
||||
const nsTArray<RefPtr<nsINode>>& AssignedNodes() const;
|
||||
void InsertAssignedNode(uint32_t aIndex, nsINode* aNode);
|
||||
void AppendAssignedNode(nsINode* aNode);
|
||||
void RemoveAssignedNode(nsINode* aNode);
|
||||
void ClearAssignedNodes();
|
||||
|
||||
protected:
|
||||
virtual ~HTMLSlotElement();
|
||||
virtual JSObject*
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div>
|
||||
<div style="border: 10px solid green">Hello</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function tweak() {
|
||||
// div with style "border: 10px solid green"
|
||||
var shadowDiv = document.createElement("div");
|
||||
shadowDiv.style.border = "10px solid green";
|
||||
|
||||
var insertionPoint = document.createElement("content");
|
||||
shadowDiv.appendChild(insertionPoint);
|
||||
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="tweak()">
|
||||
<div id="outer">Hello</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div>
|
||||
<div style="border: 10px solid green">
|
||||
<span style="background-color: purple">Hello</span>
|
||||
<span style="background-color: orange">World</span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function tweak() {
|
||||
// div with style "border: 10px solid green"
|
||||
var shadowDiv = document.createElement("div");
|
||||
shadowDiv.style.border = "10px solid green";
|
||||
|
||||
var insertionPoint = document.createElement("content");
|
||||
shadowDiv.appendChild(insertionPoint);
|
||||
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="tweak()">
|
||||
<div id="outer">
|
||||
<span style="background-color: purple">Hello</span>
|
||||
<span style="background-color: orange">World</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
shadowDiv.style.height = "100px";
|
||||
shadowDiv.style.backgroundColor = "green";
|
||||
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
var shadowDiv = document.createElement("div");
|
||||
shadowDiv.style.border = "10px solid green";
|
||||
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
|
||||
var orangeDiv = document.createElement("div");
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
var shadowDiv = document.createElement("div");
|
||||
shadowDiv.style.border = "10px solid green";
|
||||
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
|
||||
var orangeDiv = document.createElement("div");
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
var shadowDiv = document.createElement("div");
|
||||
shadowDiv.style.border = "10px solid green";
|
||||
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
|
||||
var orangeDiv = document.createElement("div");
|
||||
|
|
|
|||
11
layout/reftests/webcomponents/basic-slot-1-ref.html
Normal file
11
layout/reftests/webcomponents/basic-slot-1-ref.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body { color: green; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
This text should be green
|
||||
</body>
|
||||
</html>
|
||||
6
layout/reftests/webcomponents/basic-slot-1.html
Normal file
6
layout/reftests/webcomponents/basic-slot-1.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<slot style="color: green">This text should be green</slot>
|
||||
</body>
|
||||
</html>
|
||||
16
layout/reftests/webcomponents/basic-slot-2-ref.html
Normal file
16
layout/reftests/webcomponents/basic-slot-2-ref.html
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: green;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>There should be a green box below.</p>
|
||||
<div></div>
|
||||
</body>
|
||||
</html>
|
||||
7
layout/reftests/webcomponents/basic-slot-2.html
Normal file
7
layout/reftests/webcomponents/basic-slot-2.html
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<p>There should be a green box below.</p>
|
||||
<slot style="display: block; width: 100px; height: 100px; background: green;"></slot>
|
||||
</body>
|
||||
</html>
|
||||
8
layout/reftests/webcomponents/basic-slot-3-ref.html
Normal file
8
layout/reftests/webcomponents/basic-slot-3-ref.html
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div>
|
||||
<div style="color: green">This text should be green</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
18
layout/reftests/webcomponents/basic-slot-3.html
Normal file
18
layout/reftests/webcomponents/basic-slot-3.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function tweak() {
|
||||
var slot = document.createElement("slot");
|
||||
slot.style.color = "green";
|
||||
|
||||
var shadowRoot =
|
||||
document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(slot);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="tweak()">
|
||||
<div id="outer">This text should be green</div>
|
||||
</body>
|
||||
</html>
|
||||
20
layout/reftests/webcomponents/basic-slot-4.html
Normal file
20
layout/reftests/webcomponents/basic-slot-4.html
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function tweak() {
|
||||
var slot = document.createElement("slot");
|
||||
// The border shouldn't be visible, due to display: contents.
|
||||
slot.style.border = "1px solid red";
|
||||
slot.style.color = "green";
|
||||
|
||||
var shadowRoot =
|
||||
document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(slot);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="tweak()">
|
||||
<div id="outer">This text should be green</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -5,9 +5,11 @@
|
|||
<body>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
var host = document.getElementById("host");
|
||||
var root = host.createShadowRoot();
|
||||
root.innerHTML = 'a <content></content> c';
|
||||
var host, root;
|
||||
|
||||
host = document.getElementById("host");
|
||||
root = host.attachShadow({mode: 'open'});
|
||||
root.innerHTML = 'a <slot></slot> c';
|
||||
|
||||
function tweak() {
|
||||
var span = document.createElement("span");
|
||||
|
|
@ -19,7 +21,7 @@
|
|||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
window.addEventListener("MozReftestInvalidate", tweak, false);
|
||||
window.addEventListener("MozReftestInvalidate", tweak);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@
|
|||
<body>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
var host = document.getElementById("host");
|
||||
var root = host.createShadowRoot();
|
||||
var host, root;
|
||||
|
||||
host = document.getElementById("host");
|
||||
root = host.attachShadow({mode: 'open'});
|
||||
root.innerHTML = "<span>a</span>";
|
||||
|
||||
function tweak() {
|
||||
|
|
@ -20,7 +22,7 @@
|
|||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
window.addEventListener("MozReftestInvalidate", tweak, false);
|
||||
window.addEventListener("MozReftestInvalidate", tweak);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<div style="background-color: green"><span>Hello</span><span> </span><span>World</span></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function tweak() {
|
||||
var oldestShadow = document.getElementById('outer').createShadowRoot();
|
||||
oldestShadow.innerHTML = 'Hello';
|
||||
|
||||
var olderShadow = document.getElementById('outer').createShadowRoot();
|
||||
|
||||
var youngerShadow = document.getElementById('outer').createShadowRoot();
|
||||
youngerShadow.innerHTML = '<div style="background-color:green"><shadow></shadow></div>';
|
||||
|
||||
olderShadow.innerHTML = '<shadow></shadow> World';
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="tweak()">
|
||||
<div id="outer">
|
||||
<div style="width:300px; height:100px; background-color:red;"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -8,13 +8,13 @@
|
|||
shadowDiv.style.border = "10px solid green";
|
||||
|
||||
// Insertion point will match nothing and use fallback content.
|
||||
var insertionPoint = document.createElement("content");
|
||||
shadowDiv.appendChild(insertionPoint);
|
||||
var slot = document.createElement("slot");
|
||||
shadowDiv.appendChild(slot);
|
||||
|
||||
// Append three nodes as children to use as fallback content.
|
||||
insertionPoint.innerHTML = '<span style="background-color: orange">Hello</span> <span style="background-color: green">World</span>';
|
||||
slot.innerHTML = '<span style="background-color: orange">Hello</span> <span style="background-color: green">World</span>';
|
||||
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -5,19 +5,21 @@
|
|||
<body>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
var host = document.getElementById("host");
|
||||
var root = host.createShadowRoot();
|
||||
var host, root;
|
||||
|
||||
host = document.getElementById("host");
|
||||
root = host.attachShadow({mode: 'open'});
|
||||
root.innerHTML = '<style>input ~ div { background: red; transition: background 100ms; } input:checked ~ div { background: green; }</style><input id="one" type="checkbox"><div style="height: 50px; width: 50px;"></div>';
|
||||
|
||||
function tweak() {
|
||||
var el = root.getElementById("one");
|
||||
el.checked = true;
|
||||
el.nextSibling.addEventListener("transitionend", function() {
|
||||
document.documentElement.removeAttribute("class");
|
||||
}, false);
|
||||
var el = root.getElementById("one");
|
||||
el.checked = true;
|
||||
el.nextSibling.addEventListener("transitionend", function() {
|
||||
setTimeout(()=>{document.documentElement.removeAttribute("class")}, 1000); // wait for the checkbox SVG image to load on Android
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("MozReftestInvalidate", tweak, false);
|
||||
window.addEventListener("MozReftestInvalidate", tweak);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -7,19 +7,20 @@
|
|||
var outerShadow = document.createElement("div");
|
||||
outerShadow.style.border = "10px solid green";
|
||||
|
||||
var outerInsertionPoint = document.createElement("content");
|
||||
var outerInsertionPoint = document.createElement("slot");
|
||||
outerShadow.appendChild(outerInsertionPoint);
|
||||
|
||||
// div with style "border: 10px solid orange"
|
||||
var innerShadow = document.createElement("div");
|
||||
innerShadow.style.border = "10px solid orange";
|
||||
|
||||
var innerInsertionPoint = document.createElement("content");
|
||||
innerShadow.appendChild(innerInsertionPoint);
|
||||
var slot = document.createElement("slot");
|
||||
innerShadow.appendChild(slot);
|
||||
|
||||
outerShadow.createShadowRoot().appendChild(innerShadow);
|
||||
outerShadow.attachShadow({mode: 'open'}).appendChild(innerShadow);
|
||||
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
var shadowRoot =
|
||||
document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(outerShadow);
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
16
layout/reftests/webcomponents/reframe-shadow-child-1.html
Normal file
16
layout/reftests/webcomponents/reframe-shadow-child-1.html
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<!doctype html>
|
||||
<template id="tmpl">
|
||||
<div style="display: table">
|
||||
Some text
|
||||
<span style="display: table-cell">something</span>
|
||||
More text
|
||||
</div>
|
||||
</template>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
let shadowRoot = document.getElementById("host").attachShadow({mode: 'open'});
|
||||
let tmpl = document.getElementById("tmpl");
|
||||
shadowRoot.appendChild(document.importNode(tmpl.content, true));
|
||||
document.body.offsetTop;
|
||||
shadowRoot.firstElementChild.querySelector("span").remove();
|
||||
</script>
|
||||
15
layout/reftests/webcomponents/reframe-shadow-child-2.html
Normal file
15
layout/reftests/webcomponents/reframe-shadow-child-2.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<!doctype html>
|
||||
<template id="tmpl">
|
||||
<div style="display: block">
|
||||
Some text
|
||||
More text
|
||||
</div>
|
||||
</template>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
let shadowRoot = document.getElementById("host").attachShadow({mode: 'open'});
|
||||
let tmpl = document.getElementById("tmpl");
|
||||
shadowRoot.appendChild(document.importNode(tmpl.content, true));
|
||||
document.body.offsetTop;
|
||||
shadowRoot.firstElementChild.style.display = "table";
|
||||
</script>
|
||||
|
|
@ -3,8 +3,6 @@ pref(dom.webcomponents.enabled,true) == basic-shadow-1.html basic-shadow-1-ref.h
|
|||
pref(dom.webcomponents.enabled,true) == basic-shadow-2.html basic-shadow-2-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == basic-shadow-3.html basic-shadow-3-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == basic-shadow-4.html basic-shadow-4-ref.html
|
||||
#bug 1421542 pref(dom.webcomponents.enabled,true) == basic-insertion-point-1.html basic-insertion-point-1-ref.html
|
||||
#bug 1421542 pref(dom.webcomponents.enabled,true) == basic-insertion-point-2.html basic-insertion-point-2-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == fallback-content-1.html fallback-content-1-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == remove-insertion-point-1.html remove-insertion-point-1-ref.html
|
||||
#bug 1421542 pref(dom.webcomponents.enabled,true) == nested-insertion-point-1.html nested-insertion-point-1-ref.html
|
||||
|
|
@ -13,3 +11,9 @@ pref(dom.webcomponents.enabled,true) == input-transition-1.html input-transition
|
|||
#bug 1421542 pref(dom.webcomponents.enabled,true) == dynamic-insertion-point-distribution-1.html dynamic-insertion-point-distribution-1-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == dynamic-insertion-point-distribution-2.html dynamic-insertion-point-distribution-2-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == remove-append-shadow-host-1.html remove-append-shadow-host-1-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == basic-slot-1.html basic-slot-1-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == basic-slot-2.html basic-slot-2-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == basic-slot-3.html basic-slot-3-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == basic-slot-4.html basic-slot-3-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == basic-slot-5.html basic-slot-5-ref.html
|
||||
pref(dom.webcomponents.enabled,true) == basic-slot-6.html basic-slot-6-ref.html
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<div id="container"><div id="host"></div></div>
|
||||
<script>
|
||||
var host = document.getElementById("host");
|
||||
var root = host.createShadowRoot();
|
||||
var root = host.attachShadow({mode: 'open'});
|
||||
root.innerHTML = 'inside shadow DOM';
|
||||
|
||||
var container = document.getElementById("container");
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@
|
|||
shadowDiv.style.border = "10px solid green";
|
||||
|
||||
// Insertion point will match nothing and use fallback content.
|
||||
var insertionPoint = document.createElement("content");
|
||||
shadowDiv.appendChild(insertionPoint);
|
||||
var slot = document.createElement("slot");
|
||||
shadowDiv.appendChild(slot);
|
||||
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
|
||||
// Remove the insertion point from the ShadowRoot, "Hello" should no
|
||||
// longer be rendered.
|
||||
shadowDiv.removeChild(insertionPoint);
|
||||
shadowDiv.removeChild(slot);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
<!doctype html>
|
||||
<style>
|
||||
div { display: contents }
|
||||
</style>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<script>
|
||||
let divs = document.querySelectorAll('div');
|
||||
divs[0].attachShadow({mode: 'open'}).innerHTML = `
|
||||
<style>
|
||||
* { color: green; }
|
||||
</style>
|
||||
<span>Should be green</span>
|
||||
`;
|
||||
divs[1].attachShadow({mode: 'open'}).innerHTML = `
|
||||
<style>
|
||||
* { color: initial; }
|
||||
[foo] { }
|
||||
</style>
|
||||
<span>Should not be green</span>
|
||||
`;
|
||||
</script>
|
||||
14
layout/reftests/webcomponents/style-sharing.html
Normal file
14
layout/reftests/webcomponents/style-sharing.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
let root = host.attachShadow({mode: 'open'});
|
||||
root.innerHTML = `
|
||||
<style>
|
||||
#test {
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
<span id="test">Should be green</span>
|
||||
<span id="test2">Should not be green</span>
|
||||
`;
|
||||
</script>
|
||||
|
|
@ -5,17 +5,18 @@
|
|||
<body>
|
||||
<div id="outer"><span id="distnode">text</span></div>
|
||||
<script>
|
||||
var shadowRoot = document.getElementById('outer').createShadowRoot();
|
||||
shadowRoot.innerHTML = '<div><content></content></div>';
|
||||
|
||||
function tweak() {
|
||||
var distNode = document.getElementById("distnode");
|
||||
distNode.textContent = "Hello World";
|
||||
var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
|
||||
shadowRoot.innerHTML = '<div><slot></slot></div>';
|
||||
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
function tweak() {
|
||||
var distNode = document.getElementById("distnode");
|
||||
distNode.textContent = "Hello World";
|
||||
|
||||
window.addEventListener("MozReftestInvalidate", tweak);
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
window.addEventListener("MozReftestInvalidate", tweak);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -471,3 +471,9 @@ div:-moz-native-anonymous.moz-custom-content-container {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Shadow DOM v1
|
||||
* https://drafts.csswg.org/css-scoping/#slots-in-shadow-tree */
|
||||
slot {
|
||||
display: contents;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
[interfaces.html]
|
||||
type: testharness
|
||||
prefs: [dom.forms.inputmode:true, dom.dialog_element.enabled:true]
|
||||
prefs: [dom.forms.inputmode:true, dom.dialog_element.enabled:true, dom.webcomponents.enabled:true]
|
||||
[Document interface: attribute domain]
|
||||
expected: FAIL
|
||||
|
||||
|
|
@ -2524,21 +2524,6 @@
|
|||
[HTMLSlotElement interface: operation assignedNodes(AssignedNodesOptions)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSlotElement must be primary interface of document.createElement("slot")]
|
||||
expected: FAIL
|
||||
|
||||
[Stringification of document.createElement("slot")]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSlotElement interface: document.createElement("slot") must inherit property "name" with the proper type (0)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSlotElement interface: document.createElement("slot") must inherit property "assignedNodes" with the proper type (1)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSlotElement interface: calling assignedNodes(AssignedNodesOptions) on document.createElement("slot") with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("text") must inherit property "dirName" with the proper type (6)]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[reflection-misc.html]
|
||||
type: testharness
|
||||
prefs: [dom.dialog_element.enabled: true]
|
||||
prefs: [dom.dialog_element.enabled: true, dom.webcomponents.enabled:true]
|
||||
[html.tabIndex: setAttribute() to object "3" followed by getAttribute()]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
[HTMLSlotElement-interface.html]
|
||||
type: testharness
|
||||
[HTMLSlotElement must be defined on window]
|
||||
expected: FAIL
|
||||
|
||||
["name" attribute on HTMLSlotElement must reflect "name" attribute]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes() on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes({"flattened":false}) on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes({"flattened":true}) on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes() must return the list of assigned nodes when none of the assigned nodes themselves are slots]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes({"flattened":false}) must return the list of assigned nodes when none of the assigned nodes themselves are slots]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes({"flattened":true}) must return the list of assigned nodes when none of the assigned nodes themselves are slots]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes() must update when slot and name attributes are modified]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes({"flattened":false}) must update when slot and name attributes are modified]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes({"flattened":true}) must update when slot and name attributes are modified]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes must update when a default slot is introduced dynamically by a slot rename]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes must update when slot elements are inserted or removed]
|
||||
expected: FAIL
|
||||
|
||||
[assignedNodes({flatten: true}) must return the distributed nodes, and assignedNodes() and assignedNodes({flatten: false}) must returned the assigned nodes]
|
||||
expected: FAIL
|
||||
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
[Slotable-interface.html]
|
||||
type: testharness
|
||||
prefs: [dom.webcomponents.enabled:true]
|
||||
[assignedSlot must return null when the node does not have an assigned node]
|
||||
expected: FAIL
|
||||
|
||||
[assignedSlot must return the assigned slot]
|
||||
expected: FAIL
|
||||
|
||||
[assignedSlot must return null when the assigned slot element is inside a closed shadow tree]
|
||||
expected: FAIL
|
||||
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
[event-inside-slotted-node.html]
|
||||
type: testharness
|
||||
[Firing an event inside a grand child of a detached open mode shadow host]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event inside a grand child of a detached closed mode shadow host]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event inside a grand child of an in-document open mode shadow host]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event inside a grand child of an in-document closed mode shadow host]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event on a node with two ancestors with a detached open and open shadow trees with an inner open shadow tree]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event on a node with two ancestors with a detached open and open shadow trees with an inner closed shadow tree]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event on a node with two ancestors with a detached open and closed shadow trees with an inner open shadow tree]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event on a node with two ancestors with a detached open and closed shadow trees with an inner closed shadow tree]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event on a node with two ancestors with a detached closed and open shadow trees with an inner open shadow tree]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event on a node with two ancestors with a detached closed and open shadow trees with an inner closed shadow tree]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event on a node with two ancestors with a detached closed and closed shadow trees with an inner open shadow tree]
|
||||
expected: FAIL
|
||||
|
||||
[Firing an event on a node with two ancestors with a detached closed and closed shadow trees with an inner closed shadow tree]
|
||||
expected: FAIL
|
||||
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
[slots-fallback.html]
|
||||
type: testharness
|
||||
[Slots fallback: Basic.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots fallback: Slots in Slots.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots fallback: Fallback contents should not be used if a node is assigned.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots fallback: Slots in Slots: Assinged nodes should be used as fallback contents of another slot]
|
||||
expected: FAIL
|
||||
|
||||
[Slots fallback: Complex case.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots fallback: Mutation. Append fallback contents.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots fallback: Mutation. Remove fallback contents.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots fallback: Mutation. Assign a node to a slot so that fallback contens are no longer used.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots fallback: Mutation. Remove an assigned node from a slot so that fallback contens will be used.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots fallback: Mutation. Remove a slot which is a fallback content of another slot.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
[slots.html]
|
||||
type: testharness
|
||||
[Slots: Basic.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Slots in closed.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Slots not in a shadow tree.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Distributed nooes for Slots not in a shadow tree.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Name matching]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: No direct host child.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Default Slot.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Slot in Slot does not matter in assignment.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Slot is assigned to another slot]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Open > Closed.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Closed > Closed.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Closed > Open.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Complex case: Basi line.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: appendChild.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: Change slot= attribute 1.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: Change slot= attribute 2.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: Change slot= attribute 3.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: Remove a child.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: Add a slot: after.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: Add a slot: before.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: Remove a slot.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: Change slot name= attribute.]
|
||||
expected: FAIL
|
||||
|
||||
[Slots: Mutation: Change slot slot= attribute.]
|
||||
expected: FAIL
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue