no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / html / HTMLDetailsElement.cpp
blobafb0087e20a4bc7fac025fa4065921361908af56
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/HTMLDetailsElement.h"
9 #include "mozilla/dom/HTMLDetailsElementBinding.h"
10 #include "mozilla/dom/HTMLSummaryElement.h"
11 #include "mozilla/dom/ShadowRoot.h"
12 #include "mozilla/ScopeExit.h"
13 #include "nsContentUtils.h"
14 #include "nsTextNode.h"
16 NS_IMPL_NS_NEW_HTML_ELEMENT(Details)
18 namespace mozilla::dom {
20 HTMLDetailsElement::~HTMLDetailsElement() = default;
22 NS_IMPL_ELEMENT_CLONE(HTMLDetailsElement)
24 HTMLDetailsElement::HTMLDetailsElement(already_AddRefed<NodeInfo>&& aNodeInfo)
25 : nsGenericHTMLElement(std::move(aNodeInfo)) {
26 SetupShadowTree();
29 HTMLSummaryElement* HTMLDetailsElement::GetFirstSummary() const {
30 // XXX: Bug 1245032: Might want to cache the first summary element.
31 for (nsIContent* child = nsINode::GetFirstChild(); child;
32 child = child->GetNextSibling()) {
33 if (auto* summary = HTMLSummaryElement::FromNode(child)) {
34 return summary;
37 return nullptr;
40 void HTMLDetailsElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
41 const nsAttrValue* aValue,
42 const nsAttrValue* aOldValue,
43 nsIPrincipal* aMaybeScriptedPrincipal,
44 bool aNotify) {
45 if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::open) {
46 bool wasOpen = !!aOldValue;
47 bool isOpen = !!aValue;
48 if (wasOpen != isOpen) {
49 auto stringForState = [](bool aOpen) {
50 return aOpen ? u"open"_ns : u"closed"_ns;
52 nsAutoString oldState;
53 if (mToggleEventDispatcher) {
54 oldState.Truncate();
55 static_cast<ToggleEvent*>(mToggleEventDispatcher->mEvent.get())
56 ->GetOldState(oldState);
57 mToggleEventDispatcher->Cancel();
58 } else {
59 oldState.Assign(stringForState(wasOpen));
61 RefPtr<ToggleEvent> toggleEvent = CreateToggleEvent(
62 u"toggle"_ns, oldState, stringForState(isOpen), Cancelable::eNo);
63 mToggleEventDispatcher =
64 new AsyncEventDispatcher(this, toggleEvent.forget());
65 mToggleEventDispatcher->PostDOMEvent();
69 return nsGenericHTMLElement::AfterSetAttr(
70 aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
73 void HTMLDetailsElement::SetupShadowTree() {
74 const bool kNotify = false;
75 AttachAndSetUAShadowRoot(NotifyUAWidgetSetup::No);
76 RefPtr<ShadowRoot> sr = GetShadowRoot();
77 if (NS_WARN_IF(!sr)) {
78 return;
81 nsNodeInfoManager* nim = OwnerDoc()->NodeInfoManager();
82 RefPtr<NodeInfo> slotNodeInfo = nim->GetNodeInfo(
83 nsGkAtoms::slot, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE);
85 RefPtr<NodeInfo> linkNodeInfo = nim->GetNodeInfo(
86 nsGkAtoms::link, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE);
87 RefPtr<nsGenericHTMLElement> link =
88 NS_NewHTMLLinkElement(linkNodeInfo.forget());
89 if (NS_WARN_IF(!link)) {
90 return;
92 link->SetAttr(nsGkAtoms::rel, u"stylesheet"_ns, IgnoreErrors());
93 link->SetAttr(nsGkAtoms::href,
94 u"resource://content-accessible/details.css"_ns,
95 IgnoreErrors());
96 sr->AppendChildTo(link, kNotify, IgnoreErrors());
99 RefPtr<nsGenericHTMLElement> slot =
100 NS_NewHTMLSlotElement(do_AddRef(slotNodeInfo));
101 if (NS_WARN_IF(!slot)) {
102 return;
104 slot->SetAttr(kNameSpaceID_None, nsGkAtoms::name,
105 u"internal-main-summary"_ns, kNotify);
106 sr->AppendChildTo(slot, kNotify, IgnoreErrors());
108 RefPtr<NodeInfo> summaryNodeInfo = nim->GetNodeInfo(
109 nsGkAtoms::summary, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE);
110 RefPtr<nsGenericHTMLElement> summary =
111 NS_NewHTMLSummaryElement(summaryNodeInfo.forget());
112 if (NS_WARN_IF(!summary)) {
113 return;
116 nsAutoString defaultSummaryText;
117 nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
118 "DefaultSummary", OwnerDoc(),
119 defaultSummaryText);
120 RefPtr<nsTextNode> description = new (nim) nsTextNode(nim);
121 description->SetText(defaultSummaryText, kNotify);
122 summary->AppendChildTo(description, kNotify, IgnoreErrors());
124 slot->AppendChildTo(summary, kNotify, IgnoreErrors());
127 RefPtr<nsGenericHTMLElement> slot =
128 NS_NewHTMLSlotElement(slotNodeInfo.forget());
129 if (NS_WARN_IF(!slot)) {
130 return;
132 sr->AppendChildTo(slot, kNotify, IgnoreErrors());
136 void HTMLDetailsElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
137 if (mToggleEventDispatcher == aEvent) {
138 mToggleEventDispatcher = nullptr;
142 JSObject* HTMLDetailsElement::WrapNode(JSContext* aCx,
143 JS::Handle<JSObject*> aGivenProto) {
144 return HTMLDetailsElement_Binding::Wrap(aCx, this, aGivenProto);
147 void HTMLDetailsElement::HandleInvokeInternal(nsAtom* aAction,
148 ErrorResult& aRv) {
149 if (nsContentUtils::EqualsIgnoreASCIICase(aAction, nsGkAtoms::_auto) ||
150 nsContentUtils::EqualsIgnoreASCIICase(aAction, nsGkAtoms::toggle)) {
151 ToggleOpen();
152 } else if (nsContentUtils::EqualsIgnoreASCIICase(aAction, nsGkAtoms::close)) {
153 if (Open()) {
154 SetOpen(false, IgnoreErrors());
156 } else if (nsContentUtils::EqualsIgnoreASCIICase(aAction, nsGkAtoms::open)) {
157 if (!Open()) {
158 SetOpen(true, IgnoreErrors());
163 } // namespace mozilla::dom