diff options
author | Matt A. Tobin <email@mattatobin.com> | 2020-04-17 07:04:42 -0400 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2020-04-17 07:04:42 -0400 |
commit | 873abc7bcb6adc5cbf98ba3e1bd9a3271afc9806 (patch) | |
tree | 11bf691b4aed8b1a0834bdc7b7c1bc4eda739713 /dom | |
parent | 96dfc63bc583454fb895c7a23f685995f5410388 (diff) | |
download | uxp-873abc7bcb6adc5cbf98ba3e1bd9a3271afc9806.tar.gz |
Bug 1404842 - Implement Element.attachShadow and Element.slot
Tag #1375
Diffstat (limited to 'dom')
-rw-r--r-- | dom/base/Element.cpp | 84 | ||||
-rw-r--r-- | dom/base/Element.h | 10 | ||||
-rw-r--r-- | dom/base/ShadowRoot.cpp | 3 | ||||
-rw-r--r-- | dom/base/ShadowRoot.h | 13 | ||||
-rw-r--r-- | dom/webidl/Element.webidl | 22 | ||||
-rw-r--r-- | dom/webidl/ShadowRoot.webidl | 13 |
6 files changed, 134 insertions, 11 deletions
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index ba5ba9c721..638d6674d2 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -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(); } diff --git a/dom/base/Element.h b/dom/base/Element.h index 88f416be78..6169fbdab9 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -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(); diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp index 5f61b1f4dc..e00bb69d83 100644 --- a/dom/base/ShadowRoot.cpp +++ b/dom/base/ShadowRoot.cpp @@ -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 diff --git a/dom/base/ShadowRoot.h b/dom/base/ShadowRoot.h index 42423c92e3..f061735e2a 100644 --- a/dom/base/ShadowRoot.h +++ b/dom/base/ShadowRoot.h @@ -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 diff --git a/dom/webidl/Element.webidl b/dom/webidl/Element.webidl index 7fc59d614a..ddc5484421 100644 --- a/dom/webidl/Element.webidl +++ b/dom/webidl/Element.webidl @@ -228,16 +228,28 @@ partial interface Element { NodeList querySelectorAll(DOMString selectors); }; -// http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-element-interface +// https://dom.spec.whatwg.org/#dictdef-shadowrootinit +dictionary ShadowRootInit { + required ShadowRootMode mode; +}; + +// https://dom.spec.whatwg.org/#element partial interface Element { - [Throws,Func="nsDocument::IsWebComponentsEnabled"] - ShadowRoot createShadowRoot(); - [Func="nsDocument::IsWebComponentsEnabled"] - NodeList getDestinationInsertionPoints(); + // Shadow DOM v1 + [Throws, Pref="nsDocument::IsWebComponentsEnabled"] + ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict); [Func="nsDocument::IsWebComponentsEnabled"] readonly attribute ShadowRoot? shadowRoot; [Pref="nsDocument::IsWebComponentsEnabled"] readonly attribute HTMLSlotElement? assignedSlot; + [CEReactions, Unscopable, SetterThrows, Pref="nsDocument::IsWebComponentsEnabled"] + attribute DOMString slot; + + // [deprecated] Shadow DOM v0 + [Throws, Pref="nsDocument::IsWebComponentsEnabled"] + ShadowRoot createShadowRoot(); + [Pref="nsDocument::IsWebComponentsEnabled"] + NodeList getDestinationInsertionPoints(); }; Element implements ChildNode; diff --git a/dom/webidl/ShadowRoot.webidl b/dom/webidl/ShadowRoot.webidl index 90e6b64676..47e6cf5ec5 100644 --- a/dom/webidl/ShadowRoot.webidl +++ b/dom/webidl/ShadowRoot.webidl @@ -10,16 +10,27 @@ * liability, trademark and document use rules apply. */ +// https://dom.spec.whatwg.org/#enumdef-shadowrootmode +enum ShadowRootMode { + "open", + "closed" +}; + +// https://dom.spec.whatwg.org/#shadowroot [Func="nsDocument::IsWebComponentsEnabled"] interface ShadowRoot : DocumentFragment { + // Shadow DOM v1 + readonly attribute ShadowRootMode mode; + readonly attribute Element host; + + // [deprecated] Shadow DOM v0 Element? getElementById(DOMString elementId); HTMLCollection getElementsByTagName(DOMString localName); HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName); HTMLCollection getElementsByClassName(DOMString classNames); [CEReactions, SetterThrows, TreatNullAs=EmptyString] attribute DOMString innerHTML; - readonly attribute Element host; attribute boolean applyAuthorStyles; readonly attribute StyleSheetList styleSheets; }; |