Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / HTMLDetailsElement.cpp
1 /*
2  * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
3  *
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.
8  *
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.
13  *
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.
18  *
19  */
20
21 #include "config.h"
22 #include "core/html/HTMLDetailsElement.h"
23
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"
40
41 namespace blink {
42
43 using namespace HTMLNames;
44
45 static DetailsEventSender& detailsToggleEventSender()
46 {
47     DEFINE_STATIC_LOCAL(DetailsEventSender, sharedToggleEventSender, (EventTypeNames::toggle));
48     return sharedToggleEventSender;
49 }
50
51 PassRefPtrWillBeRawPtr<HTMLDetailsElement> HTMLDetailsElement::create(Document& document)
52 {
53     RefPtrWillBeRawPtr<HTMLDetailsElement> details = adoptRefWillBeNoop(new HTMLDetailsElement(document));
54     details->ensureUserAgentShadowRoot();
55     return details.release();
56 }
57
58 HTMLDetailsElement::HTMLDetailsElement(Document& document)
59     : HTMLElement(detailsTag, document)
60     , m_isOpen(false)
61 {
62     UseCounter::count(document, UseCounter::DetailsElement);
63 }
64
65 HTMLDetailsElement::~HTMLDetailsElement()
66 {
67     detailsToggleEventSender().cancelEvent(this);
68 }
69
70 void HTMLDetailsElement::dispatchPendingEvent(DetailsEventSender* eventSender)
71 {
72     ASSERT_UNUSED(eventSender, eventSender == &detailsToggleEventSender());
73     dispatchEvent(Event::create(EventTypeNames::toggle));
74 }
75
76
77 RenderObject* HTMLDetailsElement::createRenderer(RenderStyle*)
78 {
79     return new RenderBlockFlow(this);
80 }
81
82 void HTMLDetailsElement::didAddUserAgentShadowRoot(ShadowRoot& root)
83 {
84     DEFINE_STATIC_LOCAL(const AtomicString, summarySelector, ("summary:first-of-type", AtomicString::ConstructFromLiteral));
85
86     RefPtrWillBeRawPtr<HTMLSummaryElement> defaultSummary = HTMLSummaryElement::create(document());
87     defaultSummary->appendChild(Text::create(document(), locale().queryString(blink::WebLocalizedString::DetailsLabel)));
88
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());
94
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());
100 }
101
102 Element* HTMLDetailsElement::findMainSummary() const
103 {
104     if (HTMLSummaryElement* summary = Traversal<HTMLSummaryElement>::firstChild(*this))
105         return summary;
106
107     HTMLContentElement* content = toHTMLContentElement(userAgentShadowRoot()->firstChild());
108     ASSERT(content->firstChild() && isHTMLSummaryElement(*content->firstChild()));
109     return toElement(content->firstChild());
110 }
111
112 void HTMLDetailsElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
113 {
114     if (name == openAttr) {
115         bool oldValue = m_isOpen;
116         m_isOpen = !value.isNull();
117         if (m_isOpen == oldValue)
118             return;
119
120         // Dispatch toggle event asynchronously.
121         detailsToggleEventSender().cancelEvent(this);
122         detailsToggleEventSender().dispatchEventSoon(this);
123
124         Element* content = ensureUserAgentShadowRoot().getElementById(ShadowElementNames::detailsContent());
125         ASSERT(content);
126         if (m_isOpen)
127             content->removeInlineStyleProperty(CSSPropertyDisplay);
128         else
129             content->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
130         Element* summary = ensureUserAgentShadowRoot().getElementById(ShadowElementNames::detailsSummary());
131         ASSERT(summary);
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();
136         return;
137     }
138     HTMLElement::parseAttribute(name, value);
139 }
140
141 void HTMLDetailsElement::toggleOpen()
142 {
143     setAttribute(openAttr, m_isOpen ? nullAtom : emptyAtom);
144 }
145
146 bool HTMLDetailsElement::isInteractiveContent() const
147 {
148     return true;
149 }
150
151 }