HTMLSlotElement.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/dom/DocGroup.h"
  6. #include "mozilla/dom/HTMLSlotElement.h"
  7. #include "mozilla/dom/HTMLSlotElementBinding.h"
  8. #include "mozilla/dom/HTMLUnknownElement.h"
  9. #include "mozilla/dom/ShadowRoot.h"
  10. #include "nsGkAtoms.h"
  11. #include "nsDocument.h"
  12. nsGenericHTMLElement*
  13. NS_NewHTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
  14. mozilla::dom::FromParser aFromParser)
  15. {
  16. RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
  17. if (nsDocument::IsWebComponentsEnabled(nodeInfo->GetDocument())) {
  18. already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
  19. return new mozilla::dom::HTMLSlotElement(nodeInfoArg);
  20. }
  21. already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
  22. return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
  23. }
  24. namespace mozilla {
  25. namespace dom {
  26. HTMLSlotElement::HTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
  27. : nsGenericHTMLElement(aNodeInfo)
  28. {
  29. }
  30. HTMLSlotElement::~HTMLSlotElement()
  31. {
  32. }
  33. NS_IMPL_ADDREF_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
  34. NS_IMPL_RELEASE_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
  35. NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLSlotElement,
  36. nsGenericHTMLElement,
  37. mAssignedNodes)
  38. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLSlotElement)
  39. NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
  40. NS_IMPL_ELEMENT_CLONE(HTMLSlotElement)
  41. nsresult
  42. HTMLSlotElement::BindToTree(nsIDocument* aDocument,
  43. nsIContent* aParent,
  44. nsIContent* aBindingParent,
  45. bool aCompileEventHandlers)
  46. {
  47. RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
  48. nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
  49. aBindingParent,
  50. aCompileEventHandlers);
  51. NS_ENSURE_SUCCESS(rv, rv);
  52. ShadowRoot* containingShadow = GetContainingShadow();
  53. if (containingShadow && !oldContainingShadow) {
  54. containingShadow->AddSlot(this);
  55. }
  56. return NS_OK;
  57. }
  58. void
  59. HTMLSlotElement::UnbindFromTree(bool aDeep, bool aNullParent)
  60. {
  61. RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
  62. nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
  63. if (oldContainingShadow && !GetContainingShadow()) {
  64. oldContainingShadow->RemoveSlot(this);
  65. }
  66. }
  67. nsresult
  68. HTMLSlotElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
  69. const nsAttrValueOrString* aValue,
  70. bool aNotify)
  71. {
  72. if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::name) {
  73. if (ShadowRoot* containingShadow = GetContainingShadow()) {
  74. containingShadow->RemoveSlot(this);
  75. }
  76. }
  77. return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue,
  78. aNotify);
  79. }
  80. nsresult
  81. HTMLSlotElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
  82. const nsAttrValue* aValue,
  83. const nsAttrValue* aOldValue,
  84. bool aNotify)
  85. {
  86. if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::name) {
  87. if (ShadowRoot* containingShadow = GetContainingShadow()) {
  88. containingShadow->AddSlot(this);
  89. }
  90. }
  91. return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
  92. aOldValue, aNotify);
  93. }
  94. /**
  95. * Flatten assigned nodes given a slot, as in:
  96. * https://dom.spec.whatwg.org/#find-flattened-slotables
  97. */
  98. static void
  99. FlattenAssignedNodes(HTMLSlotElement* aSlot, nsTArray<RefPtr<nsINode>>& aNodes)
  100. {
  101. if (!aSlot->GetContainingShadow()) {
  102. return;
  103. }
  104. const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
  105. // If assignedNodes is empty, use children of slot as fallback content.
  106. if (assignedNodes.IsEmpty()) {
  107. for (nsIContent* child = aSlot->AsContent()->GetFirstChild();
  108. child;
  109. child = child->GetNextSibling()) {
  110. if (!child->IsSlotable()) {
  111. continue;
  112. }
  113. if (child->IsHTMLElement(nsGkAtoms::slot)) {
  114. FlattenAssignedNodes(HTMLSlotElement::FromContent(child), aNodes);
  115. } else {
  116. aNodes.AppendElement(child);
  117. }
  118. }
  119. return;
  120. }
  121. for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
  122. nsINode* assignedNode = assignedNodes[i];
  123. if (assignedNode->IsHTMLElement(nsGkAtoms::slot)) {
  124. FlattenAssignedNodes(
  125. HTMLSlotElement::FromContent(assignedNode->AsContent()), aNodes);
  126. } else {
  127. aNodes.AppendElement(assignedNode);
  128. }
  129. }
  130. }
  131. void
  132. HTMLSlotElement::AssignedNodes(const AssignedNodesOptions& aOptions,
  133. nsTArray<RefPtr<nsINode>>& aNodes)
  134. {
  135. if (aOptions.mFlatten) {
  136. return FlattenAssignedNodes(this, aNodes);
  137. }
  138. aNodes = mAssignedNodes;
  139. }
  140. void HTMLSlotElement::AssignedElements(const AssignedNodesOptions& aOptions,
  141. nsTArray<RefPtr<Element>>& aElements) {
  142. AutoTArray<RefPtr<nsINode>, 128> assignedNodes;
  143. AssignedNodes(aOptions, assignedNodes);
  144. for (const RefPtr<nsINode>& assignedNode : assignedNodes) {
  145. if (assignedNode->IsElement()) {
  146. aElements.AppendElement(assignedNode->AsElement());
  147. }
  148. }
  149. }
  150. const nsTArray<RefPtr<nsINode>>&
  151. HTMLSlotElement::AssignedNodes() const
  152. {
  153. return mAssignedNodes;
  154. }
  155. void
  156. HTMLSlotElement::InsertAssignedNode(uint32_t aIndex, nsINode* aNode)
  157. {
  158. mAssignedNodes.InsertElementAt(aIndex, aNode);
  159. aNode->AsContent()->SetAssignedSlot(this);
  160. }
  161. void
  162. HTMLSlotElement::AppendAssignedNode(nsINode* aNode)
  163. {
  164. mAssignedNodes.AppendElement(aNode);
  165. aNode->AsContent()->SetAssignedSlot(this);
  166. }
  167. void
  168. HTMLSlotElement::RemoveAssignedNode(nsINode* aNode)
  169. {
  170. mAssignedNodes.RemoveElement(aNode);
  171. aNode->AsContent()->SetAssignedSlot(nullptr);
  172. }
  173. void
  174. HTMLSlotElement::ClearAssignedNodes()
  175. {
  176. for (uint32_t i = 0; i < mAssignedNodes.Length(); i++) {
  177. mAssignedNodes[i]->AsContent()->SetAssignedSlot(nullptr);
  178. }
  179. mAssignedNodes.Clear();
  180. }
  181. void
  182. HTMLSlotElement::EnqueueSlotChangeEvent() const
  183. {
  184. DocGroup* docGroup = OwnerDoc()->GetDocGroup();
  185. if (!docGroup) {
  186. return;
  187. }
  188. docGroup->SignalSlotChange(this);
  189. }
  190. void
  191. HTMLSlotElement::FireSlotChangeEvent()
  192. {
  193. nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
  194. static_cast<nsIContent*>(this),
  195. NS_LITERAL_STRING("slotchange"), true,
  196. false);
  197. }
  198. JSObject*
  199. HTMLSlotElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  200. {
  201. return HTMLSlotElementBinding::Wrap(aCx, this, aGivenProto);
  202. }
  203. } // namespace dom
  204. } // namespace mozilla