| /* |
| * Copyright (C) 2010 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 "core/html/forms/BaseTemporalInputType.h" |
| |
| #include <limits> |
| #include "core/html/forms/ChooserOnlyTemporalInputTypeView.h" |
| #include "core/html/forms/HTMLInputElement.h" |
| #include "core/html/forms/MultipleFieldsTemporalInputTypeView.h" |
| #include "platform/text/PlatformLocale.h" |
| #include "platform/wtf/DateMath.h" |
| #include "platform/wtf/MathExtras.h" |
| #include "platform/wtf/Time.h" |
| #include "platform/wtf/text/WTFString.h" |
| |
| namespace blink { |
| |
| using blink::WebLocalizedString; |
| using namespace HTMLNames; |
| |
| static const int kMsecPerMinute = 60 * 1000; |
| static const int kMsecPerSecond = 1000; |
| |
| String BaseTemporalInputType::BadInputText() const { |
| return GetLocale().QueryString( |
| WebLocalizedString::kValidationBadInputForDateTime); |
| } |
| |
| InputTypeView* BaseTemporalInputType::CreateView() { |
| if (RuntimeEnabledFeatures::InputMultipleFieldsUIEnabled()) |
| return MultipleFieldsTemporalInputTypeView::Create(GetElement(), *this); |
| return ChooserOnlyTemporalInputTypeView::Create(GetElement(), *this); |
| } |
| |
| InputType::ValueMode BaseTemporalInputType::GetValueMode() const { |
| return ValueMode::kValue; |
| } |
| |
| double BaseTemporalInputType::ValueAsDate() const { |
| return ValueAsDouble(); |
| } |
| |
| void BaseTemporalInputType::SetValueAsDate(double value, |
| ExceptionState&) const { |
| GetElement().setValue(SerializeWithMilliseconds(value)); |
| } |
| |
| double BaseTemporalInputType::ValueAsDouble() const { |
| const Decimal value = ParseToNumber(GetElement().value(), Decimal::Nan()); |
| return value.IsFinite() ? value.ToDouble() |
| : DateComponents::InvalidMilliseconds(); |
| } |
| |
| void BaseTemporalInputType::SetValueAsDouble( |
| double new_value, |
| TextFieldEventBehavior event_behavior, |
| ExceptionState& exception_state) const { |
| SetValueAsDecimal(Decimal::FromDouble(new_value), event_behavior, |
| exception_state); |
| } |
| |
| bool BaseTemporalInputType::TypeMismatchFor(const String& value) const { |
| return !value.IsEmpty() && !ParseToDateComponents(value, nullptr); |
| } |
| |
| bool BaseTemporalInputType::TypeMismatch() const { |
| return TypeMismatchFor(GetElement().value()); |
| } |
| |
| String BaseTemporalInputType::RangeOverflowText(const Decimal& maximum) const { |
| return GetLocale().QueryString( |
| WebLocalizedString::kValidationRangeOverflowDateTime, |
| LocalizeValue(Serialize(maximum))); |
| } |
| |
| String BaseTemporalInputType::RangeUnderflowText(const Decimal& minimum) const { |
| return GetLocale().QueryString( |
| WebLocalizedString::kValidationRangeUnderflowDateTime, |
| LocalizeValue(Serialize(minimum))); |
| } |
| |
| Decimal BaseTemporalInputType::DefaultValueForStepUp() const { |
| return Decimal::FromDouble(ConvertToLocalTime(CurrentTimeMS())); |
| } |
| |
| bool BaseTemporalInputType::IsSteppable() const { |
| return true; |
| } |
| |
| Decimal BaseTemporalInputType::ParseToNumber( |
| const String& source, |
| const Decimal& default_value) const { |
| DateComponents date; |
| if (!ParseToDateComponents(source, &date)) |
| return default_value; |
| double msec = date.MillisecondsSinceEpoch(); |
| DCHECK(std::isfinite(msec)); |
| return Decimal::FromDouble(msec); |
| } |
| |
| bool BaseTemporalInputType::ParseToDateComponents(const String& source, |
| DateComponents* out) const { |
| if (source.IsEmpty()) |
| return false; |
| DateComponents ignored_result; |
| if (!out) |
| out = &ignored_result; |
| return ParseToDateComponentsInternal(source, out); |
| } |
| |
| String BaseTemporalInputType::Serialize(const Decimal& value) const { |
| if (!value.IsFinite()) |
| return String(); |
| DateComponents date; |
| if (!SetMillisecondToDateComponents(value.ToDouble(), &date)) |
| return String(); |
| return SerializeWithComponents(date); |
| } |
| |
| String BaseTemporalInputType::SerializeWithComponents( |
| const DateComponents& date) const { |
| Decimal step; |
| if (!GetElement().GetAllowedValueStep(&step)) |
| return date.ToString(); |
| if (step.Remainder(kMsecPerMinute).IsZero()) |
| return date.ToString(DateComponents::kNone); |
| if (step.Remainder(kMsecPerSecond).IsZero()) |
| return date.ToString(DateComponents::kSecond); |
| return date.ToString(DateComponents::kMillisecond); |
| } |
| |
| String BaseTemporalInputType::SerializeWithMilliseconds(double value) const { |
| return Serialize(Decimal::FromDouble(value)); |
| } |
| |
| String BaseTemporalInputType::LocalizeValue( |
| const String& proposed_value) const { |
| DateComponents date; |
| if (!ParseToDateComponents(proposed_value, &date)) |
| return proposed_value; |
| |
| String localized = GetElement().GetLocale().FormatDateTime(date); |
| return localized.IsEmpty() ? proposed_value : localized; |
| } |
| |
| String BaseTemporalInputType::VisibleValue() const { |
| return LocalizeValue(GetElement().value()); |
| } |
| |
| String BaseTemporalInputType::SanitizeValue( |
| const String& proposed_value) const { |
| return TypeMismatchFor(proposed_value) ? g_empty_string : proposed_value; |
| } |
| |
| bool BaseTemporalInputType::SupportsReadOnly() const { |
| return true; |
| } |
| |
| bool BaseTemporalInputType::ShouldRespectListAttribute() { |
| return true; |
| } |
| |
| bool BaseTemporalInputType::ValueMissing(const String& value) const { |
| return GetElement().IsRequired() && value.IsEmpty(); |
| } |
| |
| bool BaseTemporalInputType::ShouldShowFocusRingOnMouseFocus() const { |
| return true; |
| } |
| |
| bool BaseTemporalInputType::ShouldHaveSecondField( |
| const DateComponents& date) const { |
| StepRange step_range = CreateStepRange(kAnyIsDefaultStep); |
| return date.Second() || date.Millisecond() || |
| !step_range.Minimum() |
| .Remainder(static_cast<int>(kMsPerMinute)) |
| .IsZero() || |
| !step_range.Step().Remainder(static_cast<int>(kMsPerMinute)).IsZero(); |
| } |
| |
| } // namespace blink |