blob: 6855e102e43da2e99c46e0fbd4031d90d6e2608d [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/html/forms/date_time_chooser_impl.h"
#include "build/build_config.h"
#include "third_party/blink/public/mojom/choosers/date_time_chooser.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/strings/grit/blink_strings.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/html/forms/chooser_resource_loader.h"
#include "third_party/blink/renderer/core/html/forms/date_time_chooser_client.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page_popup.h"
#include "third_party/blink/renderer/platform/language.h"
#include "third_party/blink/renderer/platform/text/date_components.h"
#include "third_party/blink/renderer/platform/text/platform_locale.h"
#include "ui/base/ui_base_features.h"
namespace blink {
DateTimeChooserImpl::DateTimeChooserImpl(
LocalFrame* frame,
DateTimeChooserClient* client,
const DateTimeChooserParameters& parameters)
: frame_(frame),
client_(client),
popup_(nullptr),
parameters_(&parameters),
locale_(Locale::Create(parameters.locale)) {
DCHECK(RuntimeEnabledFeatures::InputMultipleFieldsUIEnabled());
DCHECK(frame_);
DCHECK(client_);
popup_ = frame_->View()->GetChromeClient()->OpenPagePopup(this);
parameters_ = nullptr;
}
DateTimeChooserImpl::~DateTimeChooserImpl() = default;
void DateTimeChooserImpl::Trace(Visitor* visitor) const {
visitor->Trace(frame_);
visitor->Trace(client_);
DateTimeChooser::Trace(visitor);
}
void DateTimeChooserImpl::EndChooser() {
if (!popup_)
return;
frame_->View()->GetChromeClient()->ClosePagePopup(popup_);
}
AXObject* DateTimeChooserImpl::RootAXObject() {
return popup_ ? popup_->RootAXObject() : nullptr;
}
static String ValueToDateTimeString(double value, AtomicString type) {
DateComponents components;
if (type == input_type_names::kDate)
components.SetMillisecondsSinceEpochForDate(value);
else if (type == input_type_names::kDatetimeLocal)
components.SetMillisecondsSinceEpochForDateTimeLocal(value);
else if (type == input_type_names::kMonth)
components.SetMonthsSinceEpoch(value);
else if (type == input_type_names::kTime)
components.SetMillisecondsSinceMidnight(value);
else if (type == input_type_names::kWeek)
components.SetMillisecondsSinceEpochForWeek(value);
else
NOTREACHED();
return components.GetType() == DateComponents::kInvalid
? String()
: components.ToString();
}
void DateTimeChooserImpl::WriteDocument(SharedBuffer* data) {
String step_string = String::Number(parameters_->step);
String step_base_string = String::Number(parameters_->step_base, 11);
String today_label_string;
String other_date_label_string;
if (parameters_->type == input_type_names::kMonth) {
today_label_string = GetLocale().QueryString(IDS_FORM_THIS_MONTH_LABEL);
other_date_label_string =
GetLocale().QueryString(IDS_FORM_OTHER_MONTH_LABEL);
} else if (parameters_->type == input_type_names::kWeek) {
today_label_string = GetLocale().QueryString(IDS_FORM_THIS_WEEK_LABEL);
other_date_label_string =
GetLocale().QueryString(IDS_FORM_OTHER_WEEK_LABEL);
} else {
today_label_string = GetLocale().QueryString(IDS_FORM_CALENDAR_TODAY);
other_date_label_string =
GetLocale().QueryString(IDS_FORM_OTHER_DATE_LABEL);
}
AddString(
"<!DOCTYPE html><head><meta charset='UTF-8'><meta name='color-scheme' "
"content='light dark'><style>\n",
data);
data->Append(ChooserResourceLoader::GetPickerCommonStyleSheet());
if (!features::IsFormControlsRefreshEnabled())
data->Append(ChooserResourceLoader::GetPickerButtonStyleSheet());
data->Append(ChooserResourceLoader::GetSuggestionPickerStyleSheet());
data->Append(ChooserResourceLoader::GetCalendarPickerStyleSheet());
if (features::IsFormControlsRefreshEnabled()) {
data->Append(ChooserResourceLoader::GetCalendarPickerRefreshStyleSheet());
if (parameters_->type == input_type_names::kTime ||
parameters_->type == input_type_names::kDatetimeLocal) {
data->Append(ChooserResourceLoader::GetTimePickerStyleSheet());
}
}
AddString(
"</style></head><body><div id=main>Loading...</div><script>\n"
"window.dialogArguments = {\n",
data);
AddProperty("anchorRectInScreen", parameters_->anchor_rect_in_screen, data);
AddProperty("zoomFactor", ScaledZoomFactor(), data);
AddProperty("min",
ValueToDateTimeString(parameters_->minimum, parameters_->type),
data);
AddProperty("max",
ValueToDateTimeString(parameters_->maximum, parameters_->type),
data);
AddProperty("step", step_string, data);
AddProperty("stepBase", step_base_string, data);
AddProperty("required", parameters_->required, data);
AddProperty(
"currentValue",
ValueToDateTimeString(parameters_->double_value, parameters_->type),
data);
AddProperty("focusedFieldIndex", parameters_->focused_field_index, data);
AddProperty("locale", parameters_->locale.GetString(), data);
AddProperty("todayLabel", today_label_string, data);
AddLocalizedProperty("clearLabel", IDS_FORM_CALENDAR_CLEAR, data);
AddLocalizedProperty("weekLabel", IDS_FORM_WEEK_NUMBER_LABEL, data);
AddLocalizedProperty("axShowMonthSelector",
IDS_AX_CALENDAR_SHOW_MONTH_SELECTOR, data);
AddLocalizedProperty("axShowNextMonth", IDS_AX_CALENDAR_SHOW_NEXT_MONTH,
data);
AddLocalizedProperty("axShowPreviousMonth",
IDS_AX_CALENDAR_SHOW_PREVIOUS_MONTH, data);
AddLocalizedProperty("axHourLabel", IDS_AX_HOUR_FIELD_TEXT, data);
AddLocalizedProperty("axMinuteLabel", IDS_AX_MINUTE_FIELD_TEXT, data);
AddLocalizedProperty("axSecondLabel", IDS_AX_SECOND_FIELD_TEXT, data);
AddLocalizedProperty("axMillisecondLabel", IDS_AX_MILLISECOND_FIELD_TEXT,
data);
AddLocalizedProperty("axAmPmLabel", IDS_AX_AM_PM_FIELD_TEXT, data);
AddProperty("weekStartDay", locale_->FirstDayOfWeek(), data);
AddProperty("shortMonthLabels", locale_->ShortMonthLabels(), data);
AddProperty("dayLabels", locale_->WeekDayShortLabels(), data);
AddProperty("ampmLabels", locale_->TimeAMPMLabels(), data);
AddProperty("isLocaleRTL", locale_->IsRTL(), data);
AddProperty("isRTL", parameters_->is_anchor_element_rtl, data);
AddProperty("isFormControlsRefreshEnabled",
features::IsFormControlsRefreshEnabled(), data);
#if defined(OS_MAC)
AddProperty("isBorderTransparent", features::IsFormControlsRefreshEnabled(),
data);
#endif
AddProperty("mode", parameters_->type.GetString(), data);
AddProperty("isAMPMFirst", parameters_->is_ampm_first, data);
AddProperty("hasAMPM", parameters_->has_ampm, data);
AddProperty("hasSecond", parameters_->has_second, data);
AddProperty("hasMillisecond", parameters_->has_millisecond, data);
if (parameters_->suggestions.size()) {
Vector<String> suggestion_values;
Vector<String> localized_suggestion_values;
Vector<String> suggestion_labels;
for (unsigned i = 0; i < parameters_->suggestions.size(); i++) {
suggestion_values.push_back(ValueToDateTimeString(
parameters_->suggestions[i]->value, parameters_->type));
localized_suggestion_values.push_back(
parameters_->suggestions[i]->localized_value);
suggestion_labels.push_back(parameters_->suggestions[i]->label);
}
AddProperty("suggestionValues", suggestion_values, data);
AddProperty("localizedSuggestionValues", localized_suggestion_values, data);
AddProperty("suggestionLabels", suggestion_labels, data);
AddProperty(
"inputWidth",
static_cast<unsigned>(parameters_->anchor_rect_in_screen.Width()),
data);
AddProperty(
"showOtherDateEntry",
LayoutTheme::GetTheme().SupportsCalendarPicker(parameters_->type),
data);
AddProperty("otherDateLabel", other_date_label_string, data);
const ComputedStyle* style = OwnerElement().GetComputedStyle();
mojom::blink::ColorScheme color_scheme =
style ? style->UsedColorScheme() : mojom::blink::ColorScheme::kLight;
AddProperty("suggestionHighlightColor",
LayoutTheme::GetTheme()
.ActiveListBoxSelectionBackgroundColor(color_scheme)
.Serialized(),
data);
AddProperty("suggestionHighlightTextColor",
LayoutTheme::GetTheme()
.ActiveListBoxSelectionForegroundColor(color_scheme)
.Serialized(),
data);
}
AddString("}\n", data);
data->Append(ChooserResourceLoader::GetPickerCommonJS());
data->Append(ChooserResourceLoader::GetSuggestionPickerJS());
if (features::IsFormControlsRefreshEnabled()) {
data->Append(ChooserResourceLoader::GetMonthPickerJS());
if (parameters_->type == input_type_names::kTime) {
data->Append(ChooserResourceLoader::GetTimePickerJS());
} else if (parameters_->type == input_type_names::kDatetimeLocal) {
data->Append(ChooserResourceLoader::GetTimePickerJS());
data->Append(ChooserResourceLoader::GetDateTimeLocalPickerJS());
}
}
data->Append(ChooserResourceLoader::GetCalendarPickerJS());
AddString("</script></body>\n", data);
}
Element& DateTimeChooserImpl::OwnerElement() {
return client_->OwnerElement();
}
ChromeClient& DateTimeChooserImpl::GetChromeClient() {
return *frame_->View()->GetChromeClient();
}
Locale& DateTimeChooserImpl::GetLocale() {
return *locale_;
}
void DateTimeChooserImpl::SetValueAndClosePopup(int num_value,
const String& string_value) {
if (num_value >= 0)
SetValue(string_value);
EndChooser();
}
void DateTimeChooserImpl::SetValue(const String& value) {
client_->DidChooseValue(value);
}
void DateTimeChooserImpl::CancelPopup() {
EndChooser();
}
void DateTimeChooserImpl::DidClosePopup() {
DCHECK(client_);
popup_ = nullptr;
client_->DidEndChooser();
}
} // namespace blink