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
)) {
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
)) {
40 void HTMLDetailsElement::AfterSetAttr(int32_t aNameSpaceID
, nsAtom
* aName
,
41 const nsAttrValue
* aValue
,
42 const nsAttrValue
* aOldValue
,
43 nsIPrincipal
* aMaybeScriptedPrincipal
,
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
) {
55 static_cast<ToggleEvent
*>(mToggleEventDispatcher
->mEvent
.get())
56 ->GetOldState(oldState
);
57 mToggleEventDispatcher
->Cancel();
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
)) {
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
)) {
92 link
->SetAttr(nsGkAtoms::rel
, u
"stylesheet"_ns
, IgnoreErrors());
93 link
->SetAttr(nsGkAtoms::href
,
94 u
"resource://content-accessible/details.css"_ns
,
96 sr
->AppendChildTo(link
, kNotify
, IgnoreErrors());
99 RefPtr
<nsGenericHTMLElement
> slot
=
100 NS_NewHTMLSlotElement(do_AddRef(slotNodeInfo
));
101 if (NS_WARN_IF(!slot
)) {
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
)) {
116 nsAutoString defaultSummaryText
;
117 nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES
,
118 "DefaultSummary", OwnerDoc(),
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
)) {
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
,
149 if (nsContentUtils::EqualsIgnoreASCIICase(aAction
, nsGkAtoms::_auto
) ||
150 nsContentUtils::EqualsIgnoreASCIICase(aAction
, nsGkAtoms::toggle
)) {
152 } else if (nsContentUtils::EqualsIgnoreASCIICase(aAction
, nsGkAtoms::close
)) {
154 SetOpen(false, IgnoreErrors());
156 } else if (nsContentUtils::EqualsIgnoreASCIICase(aAction
, nsGkAtoms::open
)) {
158 SetOpen(true, IgnoreErrors());
163 } // namespace mozilla::dom