1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "InjectedBundlePageFormClient.h"
28
29#include "APIArray.h"
30#include "ImmutableDictionary.h"
31#include "InjectedBundleNodeHandle.h"
32#include "WKAPICast.h"
33#include "WKBundleAPICast.h"
34#include <WebCore/HTMLFormElement.h>
35#include <WebCore/HTMLInputElement.h>
36#include <WebCore/HTMLTextAreaElement.h>
37
38using namespace WebCore;
39
40namespace WebKit {
41
42InjectedBundlePageFormClient::InjectedBundlePageFormClient(const WKBundlePageFormClientBase* client)
43{
44    initialize(client);
45}
46
47void InjectedBundlePageFormClient::didFocusTextField(WebPage* page, HTMLInputElement* inputElement, WebFrame* frame)
48{
49    if (!m_client.didFocusTextField)
50        return;
51
52    RefPtr<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::getOrCreate(inputElement);
53    m_client.didFocusTextField(toAPI(page), toAPI(nodeHandle.get()), toAPI(frame), m_client.base.clientInfo);
54}
55
56void InjectedBundlePageFormClient::textFieldDidBeginEditing(WebPage* page, HTMLInputElement* inputElement, WebFrame* frame)
57{
58    if (!m_client.textFieldDidBeginEditing)
59        return;
60
61    RefPtr<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::getOrCreate(inputElement);
62    m_client.textFieldDidBeginEditing(toAPI(page), toAPI(nodeHandle.get()), toAPI(frame), m_client.base.clientInfo);
63}
64
65void InjectedBundlePageFormClient::textFieldDidEndEditing(WebPage* page, HTMLInputElement* inputElement, WebFrame* frame)
66{
67    if (!m_client.textFieldDidEndEditing)
68        return;
69
70    RefPtr<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::getOrCreate(inputElement);
71    m_client.textFieldDidEndEditing(toAPI(page), toAPI(nodeHandle.get()), toAPI(frame), m_client.base.clientInfo);
72}
73
74void InjectedBundlePageFormClient::textDidChangeInTextField(WebPage* page, HTMLInputElement* inputElement, WebFrame* frame, bool initiatedByUserTyping)
75{
76    if (!m_client.textDidChangeInTextField)
77        return;
78
79    if (!initiatedByUserTyping)
80        return;
81
82    RefPtr<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::getOrCreate(inputElement);
83    m_client.textDidChangeInTextField(toAPI(page), toAPI(nodeHandle.get()), toAPI(frame), m_client.base.clientInfo);
84}
85
86void InjectedBundlePageFormClient::textDidChangeInTextArea(WebPage* page, HTMLTextAreaElement* textAreaElement, WebFrame* frame)
87{
88    if (!m_client.textDidChangeInTextArea)
89        return;
90
91    RefPtr<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::getOrCreate(textAreaElement);
92    m_client.textDidChangeInTextArea(toAPI(page), toAPI(nodeHandle.get()), toAPI(frame), m_client.base.clientInfo);
93}
94
95static WKInputFieldActionType toWKInputFieldActionType(API::InjectedBundle::FormClient::InputFieldAction action)
96{
97    switch (action) {
98    case API::InjectedBundle::FormClient::InputFieldAction::MoveUp:
99        return WKInputFieldActionTypeMoveUp;
100    case API::InjectedBundle::FormClient::InputFieldAction::MoveDown:
101        return WKInputFieldActionTypeMoveDown;
102    case API::InjectedBundle::FormClient::InputFieldAction::Cancel:
103        return WKInputFieldActionTypeCancel;
104    case API::InjectedBundle::FormClient::InputFieldAction::InsertTab:
105        return WKInputFieldActionTypeInsertTab;
106    case API::InjectedBundle::FormClient::InputFieldAction::InsertBacktab:
107        return WKInputFieldActionTypeInsertBacktab;
108    case API::InjectedBundle::FormClient::InputFieldAction::InsertNewline:
109        return WKInputFieldActionTypeInsertNewline;
110    case API::InjectedBundle::FormClient::InputFieldAction::InsertDelete:
111        return WKInputFieldActionTypeInsertDelete;
112    }
113
114    ASSERT_NOT_REACHED();
115    return WKInputFieldActionTypeCancel;
116}
117
118bool InjectedBundlePageFormClient::shouldPerformActionInTextField(WebPage* page, HTMLInputElement* inputElement, API::InjectedBundle::FormClient::InputFieldAction actionType, WebFrame* frame)
119{
120    if (!m_client.shouldPerformActionInTextField)
121        return false;
122
123    RefPtr<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::getOrCreate(inputElement);
124    return m_client.shouldPerformActionInTextField(toAPI(page), toAPI(nodeHandle.get()), toWKInputFieldActionType(actionType), toAPI(frame), m_client.base.clientInfo);
125}
126
127void InjectedBundlePageFormClient::willSendSubmitEvent(WebPage* page, HTMLFormElement* formElement, WebFrame* frame, WebFrame* sourceFrame, const Vector<std::pair<String, String>>& values)
128{
129    if (!m_client.willSendSubmitEvent)
130        return;
131
132    RefPtr<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::getOrCreate(formElement);
133
134    ImmutableDictionary::MapType map;
135    for (size_t i = 0; i < values.size(); ++i)
136        map.set(values[i].first, API::String::create(values[i].second));
137    auto textFieldsMap = ImmutableDictionary::create(WTF::move(map));
138
139    m_client.willSendSubmitEvent(toAPI(page), toAPI(nodeHandle.get()), toAPI(frame), toAPI(sourceFrame), toAPI(textFieldsMap.get()), m_client.base.clientInfo);
140}
141
142void InjectedBundlePageFormClient::willSubmitForm(WebPage* page, HTMLFormElement* formElement, WebFrame* frame, WebFrame* sourceFrame, const Vector<std::pair<String, String>>& values, RefPtr<API::Object>& userData)
143{
144    if (!m_client.willSubmitForm)
145        return;
146
147    RefPtr<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::getOrCreate(formElement);
148
149    ImmutableDictionary::MapType map;
150    for (size_t i = 0; i < values.size(); ++i)
151        map.set(values[i].first, API::String::create(values[i].second));
152    auto textFieldsMap = ImmutableDictionary::create(WTF::move(map));
153
154    WKTypeRef userDataToPass = 0;
155    m_client.willSubmitForm(toAPI(page), toAPI(nodeHandle.get()), toAPI(frame), toAPI(sourceFrame), toAPI(textFieldsMap.get()), &userDataToPass, m_client.base.clientInfo);
156    userData = adoptRef(toImpl(userDataToPass));
157}
158
159void InjectedBundlePageFormClient::didAssociateFormControls(WebPage* page, const Vector<RefPtr<WebCore::Element>>& elements)
160{
161    if (!m_client.didAssociateFormControls)
162        return;
163
164    Vector<RefPtr<API::Object>> elementHandles;
165    elementHandles.reserveInitialCapacity(elements.size());
166
167    for (const auto& element : elements)
168        elementHandles.uncheckedAppend(InjectedBundleNodeHandle::getOrCreate(element.get()));
169
170    m_client.didAssociateFormControls(toAPI(page), toAPI(API::Array::create(WTF::move(elementHandles)).get()), m_client.base.clientInfo);
171}
172
173bool InjectedBundlePageFormClient::shouldNotifyOnFormChanges(WebPage* page)
174{
175    if (!m_client.shouldNotifyOnFormChanges)
176        return false;
177
178    return m_client.shouldNotifyOnFormChanges(toAPI(page), m_client.base.clientInfo);
179}
180
181} // namespace WebKit
182