Bug 1404842 - Implement Element.attachShadow and Element.slot

Tag #1375
This commit is contained in:
Matt A. Tobin 2020-04-17 07:04:42 -04:00 • committed by Roy Tam
commit 67c4d022dc
48 changed files with 134 additions and 818 deletions

View file

@ -1092,9 +1092,78 @@ Element::RemoveFromIdTable()
}
}
void
Element::SetSlot(const nsAString& aName, ErrorResult& aError)
{
aError = SetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName, true);
}
void
Element::GetSlot(nsAString& aName)
{
GetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName);
}
// https://dom.spec.whatwg.org/#dom-element-attachshadow
already_AddRefed<ShadowRoot>
Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError)
{
/**
* 1. If context object’s namespace is not the HTML namespace,
* then throw a "NotSupportedError" DOMException.
*/
if (!IsHTMLElement()) {
aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
/**
* 2. If context object’s local name is not
* a valid custom element name, "article", "aside", "blockquote",
* "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6",
* "header", "main" "nav", "p", "section", or "span",
* then throw a "NotSupportedError" DOMException.
*/
nsIAtom* nameAtom = NodeInfo()->NameAtom();
if (!(nsContentUtils::IsCustomElementName(nameAtom) ||
nameAtom == nsGkAtoms::article ||
nameAtom == nsGkAtoms::aside ||
nameAtom == nsGkAtoms::blockquote ||
nameAtom == nsGkAtoms::body ||
nameAtom == nsGkAtoms::div ||
nameAtom == nsGkAtoms::footer ||
nameAtom == nsGkAtoms::h1 ||
nameAtom == nsGkAtoms::h2 ||
nameAtom == nsGkAtoms::h3 ||
nameAtom == nsGkAtoms::h4 ||
nameAtom == nsGkAtoms::h5 ||
nameAtom == nsGkAtoms::h6 ||
nameAtom == nsGkAtoms::header ||
nameAtom == nsGkAtoms::main ||
nameAtom == nsGkAtoms::nav ||
nameAtom == nsGkAtoms::p ||
nameAtom == nsGkAtoms::section ||
nameAtom == nsGkAtoms::span)) {
aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
return AttachShadowInternal(aInit.mMode == ShadowRootMode::Closed, aError);
}
already_AddRefed<ShadowRoot>
Element::CreateShadowRoot(ErrorResult& aError)
{
return AttachShadowInternal(false, aError);
}
already_AddRefed<ShadowRoot>
Element::AttachShadowInternal(bool aClosed, ErrorResult& aError)
{
/**
* 3. If context object is a shadow host, then throw
* an "InvalidStateError" DOMException.
*/
if (GetShadowRoot()) {
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
@ -1131,11 +1200,19 @@ Element::CreateShadowRoot(ErrorResult& aError)
// Calling SetPrototypeBinding takes ownership of protoBinding.
docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
RefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
protoBinding);
/**
* 4. Let shadow be a new shadow root whose node document is
* context object’s node document, host is context object,
* and mode is init’s mode.
*/
RefPtr<ShadowRoot> shadowRoot =
new ShadowRoot(this, aClosed, nodeInfo.forget(), protoBinding);
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
/**
* 5. Set context object’s shadow root to shadow.
*/
SetShadowRoot(shadowRoot);
// xblBinding takes ownership of docInfo.
@ -1145,6 +1222,9 @@ Element::CreateShadowRoot(ErrorResult& aError)
SetXBLBinding(xblBinding);
/**
* 6. Return shadow.
*/
return shadowRoot.forget();
}

View file

@ -471,6 +471,9 @@ protected:
mState &= ~aStates;
}
already_AddRefed<ShadowRoot> AttachShadowInternal(bool aClosed,
ErrorResult& aError);
private:
// Need to allow the ESM, nsGlobalWindow, and the focus manager to
// set our state
@ -921,6 +924,13 @@ public:
already_AddRefed<DOMRectList> GetClientRects();
already_AddRefed<DOMRect> GetBoundingClientRect();
// Shadow DOM v1
already_AddRefed<ShadowRoot> AttachShadow(const ShadowRootInit& aInit,
ErrorResult& aError);
void SetSlot(const nsAString& aName, ErrorResult& aError);
void GetSlot(nsAString& aName);
// [deprecated] Shadow DOM v0
already_AddRefed<ShadowRoot> CreateShadowRoot(ErrorResult& aError);
already_AddRefed<DestinationInsertionPointList> GetDestinationInsertionPoints();

View file

@ -51,7 +51,7 @@ NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
ShadowRoot::ShadowRoot(Element* aElement,
ShadowRoot::ShadowRoot(Element* aElement, bool aClosed,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding)
: DocumentFragment(aNodeInfo)
@ -60,6 +60,7 @@ ShadowRoot::ShadowRoot(Element* aElement,
, mIsComposedDocParticipant(false)
{
SetHost(aElement);
mMode = aClosed ? ShadowRootMode::Closed : ShadowRootMode::Open;
// Nodes in a shadow tree should never store a value
// in the subtree root pointer, nodes in the shadow tree

View file

@ -41,10 +41,18 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
ShadowRoot(Element* aElement,
ShadowRoot(Element* aElement, bool aClosed,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding);
// Shadow DOM v1
Element* Host();
ShadowRootMode Mode()
{
return mMode;
}
// [deprecated] Shadow DOM v0
void AddToIdTable(Element* aElement, nsIAtom* aId);
void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
@ -121,7 +129,6 @@ public:
GetElementsByClassName(const nsAString& aClasses);
void GetInnerHTML(nsAString& aInnerHTML);
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
Element* Host();
void StyleSheetChanged();
bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
@ -133,6 +140,8 @@ public:
protected:
virtual ~ShadowRoot();
ShadowRootMode mMode;
// An array of content insertion points that are a descendant of the ShadowRoot
// sorted in tree order. Insertion points are responsible for notifying
// the ShadowRoot when they are removed or added as a descendant. The insertion