/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/HTMLDetailsElement.h" #include "mozilla/dom/HTMLDetailsElementBinding.h" #include "mozilla/dom/HTMLSummaryElement.h" #include "mozilla/dom/ShadowRoot.h" #include "mozilla/ScopeExit.h" #include "nsContentUtils.h" #include "nsTextNode.h" NS_IMPL_NS_NEW_HTML_ELEMENT(Details) namespace mozilla::dom { HTMLDetailsElement::~HTMLDetailsElement() = default; NS_IMPL_ELEMENT_CLONE(HTMLDetailsElement) HTMLDetailsElement::HTMLDetailsElement(already_AddRefed&& aNodeInfo) : nsGenericHTMLElement(std::move(aNodeInfo)) { SetupShadowTree(); } HTMLSummaryElement* HTMLDetailsElement::GetFirstSummary() const { // XXX: Bug 1245032: Might want to cache the first summary element. for (nsIContent* child = nsINode::GetFirstChild(); child; child = child->GetNextSibling()) { if (auto* summary = HTMLSummaryElement::FromNode(child)) { return summary; } } return nullptr; } void HTMLDetailsElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAttrValue* aValue, const nsAttrValue* aOldValue, nsIPrincipal* aMaybeScriptedPrincipal, bool aNotify) { if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::open) { bool wasOpen = !!aOldValue; bool isOpen = !!aValue; if (wasOpen != isOpen) { if (mToggleEventDispatcher) { mToggleEventDispatcher->Cancel(); } // According to the html spec, a 'toggle' event is a simple event which // does not bubble. mToggleEventDispatcher = new AsyncEventDispatcher(this, u"toggle"_ns, CanBubble::eNo); mToggleEventDispatcher->PostDOMEvent(); } } return nsGenericHTMLElement::AfterSetAttr( aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify); } void HTMLDetailsElement::SetupShadowTree() { const bool kNotify = false; AttachAndSetUAShadowRoot(NotifyUAWidgetSetup::No); RefPtr sr = GetShadowRoot(); if (NS_WARN_IF(!sr)) { return; } nsNodeInfoManager* nim = OwnerDoc()->NodeInfoManager(); RefPtr slotNodeInfo = nim->GetNodeInfo( nsGkAtoms::slot, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE); { RefPtr linkNodeInfo = nim->GetNodeInfo( nsGkAtoms::link, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE); RefPtr link = NS_NewHTMLLinkElement(linkNodeInfo.forget()); if (NS_WARN_IF(!link)) { return; } link->SetAttr(nsGkAtoms::rel, u"stylesheet"_ns, IgnoreErrors()); link->SetAttr(nsGkAtoms::href, u"resource://content-accessible/details.css"_ns, IgnoreErrors()); sr->AppendChildTo(link, kNotify, IgnoreErrors()); } { RefPtr slot = NS_NewHTMLSlotElement(do_AddRef(slotNodeInfo)); if (NS_WARN_IF(!slot)) { return; } slot->SetAttr(kNameSpaceID_None, nsGkAtoms::name, u"internal-main-summary"_ns, kNotify); sr->AppendChildTo(slot, kNotify, IgnoreErrors()); RefPtr summaryNodeInfo = nim->GetNodeInfo( nsGkAtoms::summary, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE); RefPtr summary = NS_NewHTMLSummaryElement(summaryNodeInfo.forget()); if (NS_WARN_IF(!summary)) { return; } nsAutoString defaultSummaryText; nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES, "DefaultSummary", defaultSummaryText); RefPtr description = new (nim) nsTextNode(nim); description->SetText(defaultSummaryText, kNotify); summary->AppendChildTo(description, kNotify, IgnoreErrors()); slot->AppendChildTo(summary, kNotify, IgnoreErrors()); } { RefPtr slot = NS_NewHTMLSlotElement(slotNodeInfo.forget()); if (NS_WARN_IF(!slot)) { return; } sr->AppendChildTo(slot, kNotify, IgnoreErrors()); } } void HTMLDetailsElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) { if (mToggleEventDispatcher == aEvent) { mToggleEventDispatcher = nullptr; } } JSObject* HTMLDetailsElement::WrapNode(JSContext* aCx, JS::Handle aGivenProto) { return HTMLDetailsElement_Binding::Wrap(aCx, this, aGivenProto); } } // namespace mozilla::dom