DOM event handling should pass Event around by reference.
[WebKit-https.git] / Source / WebCore / html / HTMLSummaryElement.cpp
1 /*
2  * Copyright (C) 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 "HTMLSummaryElement.h"
23
24 #if ENABLE(DETAILS_ELEMENT)
25 #include "DetailsMarkerControl.h"
26 #include "EventNames.h"
27 #include "HTMLDetailsElement.h"
28 #include "HTMLFormControlElement.h"
29 #include "HTMLSlotElement.h"
30 #include "KeyboardEvent.h"
31 #include "MouseEvent.h"
32 #include "PlatformMouseEvent.h"
33 #include "RenderBlockFlow.h"
34 #include "ShadowRoot.h"
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
40 Ref<HTMLSummaryElement> HTMLSummaryElement::create(const QualifiedName& tagName, Document& document)
41 {
42     Ref<HTMLSummaryElement> summary = adoptRef(*new HTMLSummaryElement(tagName, document));
43     summary->addShadowRoot(ShadowRoot::create(document, ShadowRoot::Mode::UserAgent));
44     return summary;
45 }
46
47 HTMLSummaryElement::HTMLSummaryElement(const QualifiedName& tagName, Document& document)
48     : HTMLElement(tagName, document)
49 {
50     ASSERT(hasTagName(summaryTag));
51 }
52
53 RenderPtr<RenderElement> HTMLSummaryElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
54 {
55     return createRenderer<RenderBlockFlow>(*this, WTFMove(style));
56 }
57
58 void HTMLSummaryElement::didAddUserAgentShadowRoot(ShadowRoot* root)
59 {
60     root->appendChild(DetailsMarkerControl::create(document()), ASSERT_NO_EXCEPTION);
61     root->appendChild(HTMLSlotElement::create(slotTag, document()));
62 }
63
64 HTMLDetailsElement* HTMLSummaryElement::detailsElement() const
65 {
66     auto* parent = parentElement();
67     if (parent && is<HTMLDetailsElement>(*parent))
68         return downcast<HTMLDetailsElement>(parent);
69     // Fallback summary element is in the shadow tree.
70     auto* host = shadowHost();
71     if (host && is<HTMLDetailsElement>(*host))
72         return downcast<HTMLDetailsElement>(host);
73     return nullptr;
74 }
75
76 bool HTMLSummaryElement::isActiveSummary() const
77 {
78     HTMLDetailsElement* details = detailsElement();
79     if (!details)
80         return false;
81     return details->isActiveSummary(*this);
82 }
83
84 static bool isClickableControl(Node* node)
85 {
86     ASSERT(node);
87     if (!is<Element>(*node))
88         return false;
89     Element& element = downcast<Element>(*node);
90     if (is<HTMLFormControlElement>(element))
91         return true;
92     Element* host = element.shadowHost();
93     return host && is<HTMLFormControlElement>(host);
94 }
95
96 bool HTMLSummaryElement::supportsFocus() const
97 {
98     return isActiveSummary();
99 }
100
101 void HTMLSummaryElement::defaultEventHandler(Event& event)
102 {
103     if (isActiveSummary() && renderer()) {
104         if (event.type() == eventNames().DOMActivateEvent && !isClickableControl(event.target()->toNode())) {
105             if (HTMLDetailsElement* details = detailsElement())
106                 details->toggleOpen();
107             event.setDefaultHandled();
108             return;
109         }
110
111         if (is<KeyboardEvent>(event)) {
112             KeyboardEvent& keyboardEvent = downcast<KeyboardEvent>(event);
113             if (keyboardEvent.type() == eventNames().keydownEvent && keyboardEvent.keyIdentifier() == "U+0020") {
114                 setActive(true, true);
115                 // No setDefaultHandled() - IE dispatches a keypress in this case.
116                 return;
117             }
118             if (keyboardEvent.type() == eventNames().keypressEvent) {
119                 switch (keyboardEvent.charCode()) {
120                 case '\r':
121                     dispatchSimulatedClick(&event);
122                     keyboardEvent.setDefaultHandled();
123                     return;
124                 case ' ':
125                     // Prevent scrolling down the page.
126                     keyboardEvent.setDefaultHandled();
127                     return;
128                 }
129             }
130             if (keyboardEvent.type() == eventNames().keyupEvent && keyboardEvent.keyIdentifier() == "U+0020") {
131                 if (active())
132                     dispatchSimulatedClick(&event);
133                 keyboardEvent.setDefaultHandled();
134                 return;
135             }
136         }
137     }
138
139     HTMLElement::defaultEventHandler(event);
140 }
141
142 bool HTMLSummaryElement::willRespondToMouseClickEvents()
143 {
144     if (isActiveSummary() && renderer())
145         return true;
146
147     return HTMLElement::willRespondToMouseClickEvents();
148 }
149
150 }
151
152 #endif