2 * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 #include "core/html/HTMLDetailsElement.h"
24 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
25 #include "core/CSSPropertyNames.h"
26 #include "core/CSSValueKeywords.h"
27 #include "core/HTMLNames.h"
28 #include "core/dom/ElementTraversal.h"
29 #include "core/dom/Text.h"
30 #include "core/dom/shadow/ShadowRoot.h"
31 #include "core/events/Event.h"
32 #include "core/events/EventSender.h"
33 #include "core/frame/UseCounter.h"
34 #include "core/html/HTMLContentElement.h"
35 #include "core/html/HTMLDivElement.h"
36 #include "core/html/HTMLSummaryElement.h"
37 #include "core/html/shadow/ShadowElementNames.h"
38 #include "core/rendering/RenderBlockFlow.h"
39 #include "platform/text/PlatformLocale.h"
43 using namespace HTMLNames;
45 static DetailsEventSender& detailsToggleEventSender()
47 DEFINE_STATIC_LOCAL(DetailsEventSender, sharedToggleEventSender, (EventTypeNames::toggle));
48 return sharedToggleEventSender;
51 PassRefPtrWillBeRawPtr<HTMLDetailsElement> HTMLDetailsElement::create(Document& document)
53 RefPtrWillBeRawPtr<HTMLDetailsElement> details = adoptRefWillBeNoop(new HTMLDetailsElement(document));
54 details->ensureUserAgentShadowRoot();
55 return details.release();
58 HTMLDetailsElement::HTMLDetailsElement(Document& document)
59 : HTMLElement(detailsTag, document)
62 UseCounter::count(document, UseCounter::DetailsElement);
65 HTMLDetailsElement::~HTMLDetailsElement()
67 detailsToggleEventSender().cancelEvent(this);
70 void HTMLDetailsElement::dispatchPendingEvent(DetailsEventSender* eventSender)
72 ASSERT_UNUSED(eventSender, eventSender == &detailsToggleEventSender());
73 dispatchEvent(Event::create(EventTypeNames::toggle));
77 RenderObject* HTMLDetailsElement::createRenderer(RenderStyle*)
79 return new RenderBlockFlow(this);
82 void HTMLDetailsElement::didAddUserAgentShadowRoot(ShadowRoot& root)
84 DEFINE_STATIC_LOCAL(const AtomicString, summarySelector, ("summary:first-of-type", AtomicString::ConstructFromLiteral));
86 RefPtrWillBeRawPtr<HTMLSummaryElement> defaultSummary = HTMLSummaryElement::create(document());
87 defaultSummary->appendChild(Text::create(document(), locale().queryString(blink::WebLocalizedString::DetailsLabel)));
89 RefPtrWillBeRawPtr<HTMLContentElement> summary = HTMLContentElement::create(document());
90 summary->setIdAttribute(ShadowElementNames::detailsSummary());
91 summary->setAttribute(selectAttr, summarySelector);
92 summary->appendChild(defaultSummary);
93 root.appendChild(summary.release());
95 RefPtrWillBeRawPtr<HTMLDivElement> content = HTMLDivElement::create(document());
96 content->setIdAttribute(ShadowElementNames::detailsContent());
97 content->appendChild(HTMLContentElement::create(document()));
98 content->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
99 root.appendChild(content.release());
102 Element* HTMLDetailsElement::findMainSummary() const
104 if (HTMLSummaryElement* summary = Traversal<HTMLSummaryElement>::firstChild(*this))
107 HTMLContentElement* content = toHTMLContentElement(userAgentShadowRoot()->firstChild());
108 ASSERT(content->firstChild() && isHTMLSummaryElement(*content->firstChild()));
109 return toElement(content->firstChild());
112 void HTMLDetailsElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
114 if (name == openAttr) {
115 bool oldValue = m_isOpen;
116 m_isOpen = !value.isNull();
117 if (m_isOpen == oldValue)
120 // Dispatch toggle event asynchronously.
121 detailsToggleEventSender().cancelEvent(this);
122 detailsToggleEventSender().dispatchEventSoon(this);
124 Element* content = ensureUserAgentShadowRoot().getElementById(ShadowElementNames::detailsContent());
127 content->removeInlineStyleProperty(CSSPropertyDisplay);
129 content->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
130 Element* summary = ensureUserAgentShadowRoot().getElementById(ShadowElementNames::detailsSummary());
132 // FIXME: DetailsMarkerControl's RenderDetailsMarker has no concept of being updated
133 // without recreating it causing a repaint. Instead we should change it so we can tell
134 // it to toggle the open/closed triangle state and avoid reattaching the entire summary.
135 summary->lazyReattachIfAttached();
138 HTMLElement::parseAttribute(name, value);
141 void HTMLDetailsElement::toggleOpen()
143 setAttribute(openAttr, m_isOpen ? nullAtom : emptyAtom);
146 bool HTMLDetailsElement::isInteractiveContent() const