1/*
2 * Copyright (C) 2012 Google 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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
33#include "web/DateTimeChooserImpl.h"
34
35#include "core/InputTypeNames.h"
36#include "core/frame/FrameView.h"
37#include "core/html/forms/DateTimeChooserClient.h"
38#include "core/page/PagePopup.h"
39#include "core/rendering/RenderTheme.h"
40#include "platform/DateComponents.h"
41#include "platform/Language.h"
42#include "platform/text/PlatformLocale.h"
43#include "public/platform/Platform.h"
44#include "web/ChromeClientImpl.h"
45#include "web/WebViewImpl.h"
46
47namespace blink {
48
49DateTimeChooserImpl::DateTimeChooserImpl(ChromeClientImpl* chromeClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
50    : m_chromeClient(chromeClient)
51    , m_client(client)
52    , m_popup(0)
53    , m_parameters(parameters)
54    , m_locale(Locale::create(parameters.locale))
55{
56    ASSERT(m_chromeClient);
57    ASSERT(m_client);
58    m_popup = m_chromeClient->openPagePopup(this, m_parameters.anchorRectInRootView);
59}
60
61PassRefPtr<DateTimeChooserImpl> DateTimeChooserImpl::create(ChromeClientImpl* chromeClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
62{
63    return adoptRef(new DateTimeChooserImpl(chromeClient, client, parameters));
64}
65
66DateTimeChooserImpl::~DateTimeChooserImpl()
67{
68}
69
70void DateTimeChooserImpl::endChooser()
71{
72    if (!m_popup)
73        return;
74    m_chromeClient->closePagePopup(m_popup);
75}
76
77AXObject* DateTimeChooserImpl::rootAXObject()
78{
79    return m_popup ? m_popup->rootAXObject() : 0;
80}
81
82IntSize DateTimeChooserImpl::contentSize()
83{
84    return IntSize(0, 0);
85}
86
87static String valueToDateTimeString(double value, AtomicString type)
88{
89    DateComponents components;
90    if (type == InputTypeNames::date)
91        components.setMillisecondsSinceEpochForDate(value);
92    else if (type == InputTypeNames::datetime_local)
93        components.setMillisecondsSinceEpochForDateTimeLocal(value);
94    else if (type == InputTypeNames::month)
95        components.setMonthsSinceEpoch(value);
96    else if (type == InputTypeNames::time)
97        components.setMillisecondsSinceMidnight(value);
98    else if (type == InputTypeNames::week)
99        components.setMillisecondsSinceEpochForWeek(value);
100    else
101        ASSERT_NOT_REACHED();
102    return components.type() == DateComponents::Invalid ? String() : components.toString();
103}
104
105void DateTimeChooserImpl::writeDocument(SharedBuffer* data)
106{
107    String stepString = String::number(m_parameters.step);
108    String stepBaseString = String::number(m_parameters.stepBase, 11, WTF::TruncateTrailingZeros);
109    IntRect anchorRectInScreen = m_chromeClient->rootViewToScreen(m_parameters.anchorRectInRootView);
110    String todayLabelString;
111    String otherDateLabelString;
112    if (m_parameters.type == InputTypeNames::month) {
113        todayLabelString = locale().queryString(WebLocalizedString::ThisMonthButtonLabel);
114        otherDateLabelString = locale().queryString(WebLocalizedString::OtherMonthLabel);
115    } else if (m_parameters.type == InputTypeNames::week) {
116        todayLabelString = locale().queryString(WebLocalizedString::ThisWeekButtonLabel);
117        otherDateLabelString = locale().queryString(WebLocalizedString::OtherWeekLabel);
118    } else {
119        todayLabelString = locale().queryString(WebLocalizedString::CalendarToday);
120        otherDateLabelString = locale().queryString(WebLocalizedString::OtherDateLabel);
121    }
122
123    addString("<!DOCTYPE html><head><meta charset='UTF-8'><style>\n", data);
124    data->append(Platform::current()->loadResource("pickerCommon.css"));
125    data->append(Platform::current()->loadResource("pickerButton.css"));
126    data->append(Platform::current()->loadResource("suggestionPicker.css"));
127    data->append(Platform::current()->loadResource("calendarPicker.css"));
128    addString("</style></head><body><div id=main>Loading...</div><script>\n"
129        "window.dialogArguments = {\n", data);
130    addProperty("anchorRectInScreen", anchorRectInScreen, data);
131    addProperty("min", valueToDateTimeString(m_parameters.minimum, m_parameters.type), data);
132    addProperty("max", valueToDateTimeString(m_parameters.maximum, m_parameters.type), data);
133    addProperty("step", stepString, data);
134    addProperty("stepBase", stepBaseString, data);
135    addProperty("required", m_parameters.required, data);
136    addProperty("currentValue", valueToDateTimeString(m_parameters.doubleValue, m_parameters.type), data);
137    addProperty("locale", m_parameters.locale.string(), data);
138    addProperty("todayLabel", todayLabelString, data);
139    addProperty("clearLabel", locale().queryString(WebLocalizedString::CalendarClear), data);
140    addProperty("weekLabel", locale().queryString(WebLocalizedString::WeekNumberLabel), data);
141    addProperty("axShowMonthSelector", locale().queryString(WebLocalizedString::AXCalendarShowMonthSelector), data);
142    addProperty("axShowNextMonth", locale().queryString(WebLocalizedString::AXCalendarShowNextMonth), data);
143    addProperty("axShowPreviousMonth", locale().queryString(WebLocalizedString::AXCalendarShowPreviousMonth), data);
144    addProperty("weekStartDay", m_locale->firstDayOfWeek(), data);
145    addProperty("shortMonthLabels", m_locale->shortMonthLabels(), data);
146    addProperty("dayLabels", m_locale->weekDayShortLabels(), data);
147    addProperty("isLocaleRTL", m_locale->isRTL(), data);
148    addProperty("isRTL", m_parameters.isAnchorElementRTL, data);
149    addProperty("mode", m_parameters.type.string(), data);
150    if (m_parameters.suggestions.size()) {
151        Vector<String> suggestionValues;
152        Vector<String> localizedSuggestionValues;
153        Vector<String> suggestionLabels;
154        for (unsigned i = 0; i < m_parameters.suggestions.size(); i++) {
155            suggestionValues.append(valueToDateTimeString(m_parameters.suggestions[i].value, m_parameters.type));
156            localizedSuggestionValues.append(m_parameters.suggestions[i].localizedValue);
157            suggestionLabels.append(m_parameters.suggestions[i].label);
158        }
159        addProperty("suggestionValues", suggestionValues, data);
160        addProperty("localizedSuggestionValues", localizedSuggestionValues, data);
161        addProperty("suggestionLabels", suggestionLabels, data);
162        addProperty("inputWidth", static_cast<unsigned>(m_parameters.anchorRectInRootView.width()), data);
163        addProperty("showOtherDateEntry", RenderTheme::theme().supportsCalendarPicker(m_parameters.type), data);
164        addProperty("otherDateLabel", otherDateLabelString, data);
165        addProperty("suggestionHighlightColor", RenderTheme::theme().activeListBoxSelectionBackgroundColor().serialized(), data);
166        addProperty("suggestionHighlightTextColor", RenderTheme::theme().activeListBoxSelectionForegroundColor().serialized(), data);
167    }
168    addString("}\n", data);
169
170    data->append(Platform::current()->loadResource("pickerCommon.js"));
171    data->append(Platform::current()->loadResource("suggestionPicker.js"));
172    data->append(Platform::current()->loadResource("calendarPicker.js"));
173    addString("</script></body>\n", data);
174}
175
176Element& DateTimeChooserImpl::ownerElement()
177{
178    return m_client->ownerElement();
179}
180
181Locale& DateTimeChooserImpl::locale()
182{
183    return *m_locale;
184}
185
186void DateTimeChooserImpl::setValueAndClosePopup(int numValue, const String& stringValue)
187{
188    RefPtr<DateTimeChooserImpl> protector(this);
189    if (numValue >= 0)
190        setValue(stringValue);
191    endChooser();
192}
193
194void DateTimeChooserImpl::setValue(const String& value)
195{
196    m_client->didChooseValue(value);
197}
198
199void DateTimeChooserImpl::closePopup()
200{
201    endChooser();
202}
203
204void DateTimeChooserImpl::didClosePopup()
205{
206    ASSERT(m_client);
207    m_popup = 0;
208    m_client->didEndChooser();
209}
210
211} // namespace blink
212
213#endif // ENABLE(INPUT_MULTIPLE_FIELDS_UI)
214