1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
6 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7 * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB.  If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include "config.h"
27#include "core/html/HTMLButtonElement.h"
28
29#include "bindings/core/v8/V8DOMActivityLogger.h"
30#include "core/HTMLNames.h"
31#include "core/dom/Attribute.h"
32#include "core/events/KeyboardEvent.h"
33#include "core/html/FormDataList.h"
34#include "core/html/HTMLFormElement.h"
35#include "core/rendering/RenderButton.h"
36#include "wtf/StdLibExtras.h"
37
38namespace blink {
39
40using namespace HTMLNames;
41
42inline HTMLButtonElement::HTMLButtonElement(Document& document, HTMLFormElement* form)
43    : HTMLFormControlElement(buttonTag, document, form)
44    , m_type(SUBMIT)
45    , m_isActivatedSubmit(false)
46{
47}
48
49PassRefPtrWillBeRawPtr<HTMLButtonElement> HTMLButtonElement::create(Document& document, HTMLFormElement* form)
50{
51    return adoptRefWillBeNoop(new HTMLButtonElement(document, form));
52}
53
54void HTMLButtonElement::setType(const AtomicString& type)
55{
56    setAttribute(typeAttr, type);
57}
58
59RenderObject* HTMLButtonElement::createRenderer(RenderStyle*)
60{
61    return new RenderButton(this);
62}
63
64const AtomicString& HTMLButtonElement::formControlType() const
65{
66    switch (m_type) {
67        case SUBMIT: {
68            DEFINE_STATIC_LOCAL(const AtomicString, submit, ("submit", AtomicString::ConstructFromLiteral));
69            return submit;
70        }
71        case BUTTON: {
72            DEFINE_STATIC_LOCAL(const AtomicString, button, ("button", AtomicString::ConstructFromLiteral));
73            return button;
74        }
75        case RESET: {
76            DEFINE_STATIC_LOCAL(const AtomicString, reset, ("reset", AtomicString::ConstructFromLiteral));
77            return reset;
78        }
79    }
80
81    ASSERT_NOT_REACHED();
82    return emptyAtom;
83}
84
85bool HTMLButtonElement::isPresentationAttribute(const QualifiedName& name) const
86{
87    if (name == alignAttr) {
88        // Don't map 'align' attribute.  This matches what Firefox and IE do, but not Opera.
89        // See http://bugs.webkit.org/show_bug.cgi?id=12071
90        return false;
91    }
92
93    return HTMLFormControlElement::isPresentationAttribute(name);
94}
95
96void HTMLButtonElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
97{
98    if (name == typeAttr) {
99        if (equalIgnoringCase(value, "reset"))
100            m_type = RESET;
101        else if (equalIgnoringCase(value, "button"))
102            m_type = BUTTON;
103        else
104            m_type = SUBMIT;
105        setNeedsWillValidateCheck();
106    } else
107        HTMLFormControlElement::parseAttribute(name, value);
108}
109
110void HTMLButtonElement::defaultEventHandler(Event* event)
111{
112    if (event->type() == EventTypeNames::DOMActivate && !isDisabledFormControl()) {
113        if (form() && m_type == SUBMIT) {
114            m_isActivatedSubmit = true;
115            form()->prepareForSubmission(event);
116            event->setDefaultHandled();
117            m_isActivatedSubmit = false; // Do this in case submission was canceled.
118        }
119        if (form() && m_type == RESET) {
120            form()->reset();
121            event->setDefaultHandled();
122        }
123    }
124
125    if (event->isKeyboardEvent()) {
126        if (event->type() == EventTypeNames::keydown && toKeyboardEvent(event)->keyIdentifier() == "U+0020") {
127            setActive(true);
128            // No setDefaultHandled() - IE dispatches a keypress in this case.
129            return;
130        }
131        if (event->type() == EventTypeNames::keypress) {
132            switch (toKeyboardEvent(event)->charCode()) {
133                case '\r':
134                    dispatchSimulatedClick(event);
135                    event->setDefaultHandled();
136                    return;
137                case ' ':
138                    // Prevent scrolling down the page.
139                    event->setDefaultHandled();
140                    return;
141            }
142        }
143        if (event->type() == EventTypeNames::keyup && toKeyboardEvent(event)->keyIdentifier() == "U+0020") {
144            if (active())
145                dispatchSimulatedClick(event);
146            event->setDefaultHandled();
147            return;
148        }
149    }
150
151    HTMLFormControlElement::defaultEventHandler(event);
152}
153
154bool HTMLButtonElement::willRespondToMouseClickEvents()
155{
156    if (!isDisabledFormControl() && form() && (m_type == SUBMIT || m_type == RESET))
157        return true;
158    return HTMLFormControlElement::willRespondToMouseClickEvents();
159}
160
161bool HTMLButtonElement::canBeSuccessfulSubmitButton() const
162{
163    return m_type == SUBMIT;
164}
165
166bool HTMLButtonElement::isActivatedSubmit() const
167{
168    return m_isActivatedSubmit;
169}
170
171void HTMLButtonElement::setActivatedSubmit(bool flag)
172{
173    m_isActivatedSubmit = flag;
174}
175
176bool HTMLButtonElement::appendFormData(FormDataList& formData, bool)
177{
178    if (m_type != SUBMIT || name().isEmpty() || !m_isActivatedSubmit)
179        return false;
180    formData.appendData(name(), value());
181    return true;
182}
183
184void HTMLButtonElement::accessKeyAction(bool sendMouseEvents)
185{
186    focus();
187
188    dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
189}
190
191bool HTMLButtonElement::isURLAttribute(const Attribute& attribute) const
192{
193    return attribute.name() == formactionAttr || HTMLFormControlElement::isURLAttribute(attribute);
194}
195
196const AtomicString& HTMLButtonElement::value() const
197{
198    return getAttribute(valueAttr);
199}
200
201bool HTMLButtonElement::recalcWillValidate() const
202{
203    return m_type == SUBMIT && HTMLFormControlElement::recalcWillValidate();
204}
205
206bool HTMLButtonElement::isInteractiveContent() const
207{
208    return true;
209}
210
211bool HTMLButtonElement::supportsAutofocus() const
212{
213    return true;
214}
215
216Node::InsertionNotificationRequest HTMLButtonElement::insertedInto(ContainerNode* insertionPoint)
217{
218    if (insertionPoint->inDocument()) {
219        V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
220        if (activityLogger) {
221            Vector<String> argv;
222            argv.append("button");
223            argv.append(fastGetAttribute(typeAttr));
224            argv.append(fastGetAttribute(formmethodAttr));
225            argv.append(fastGetAttribute(formactionAttr));
226            activityLogger->logEvent("blinkAddElement", argv.size(), argv.data());
227        }
228    }
229    return HTMLFormControlElement::insertedInto(insertionPoint);
230}
231
232void HTMLButtonElement::attributeWillChange(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
233{
234    if (name == formactionAttr && inDocument()) {
235        V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
236        if (activityLogger) {
237            Vector<String> argv;
238            argv.append("button");
239            argv.append(formactionAttr.toString());
240            argv.append(oldValue);
241            argv.append(newValue);
242            activityLogger->logEvent("blinkSetAttribute", argv.size(), argv.data());
243        }
244    }
245    HTMLFormControlElement::attributeWillChange(name, oldValue, newValue);
246}
247
248} // namespace
249