1 /* 2 * Copyright (C) 2010 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 #include "core/html/TimeInputType.h" 33 34 #include "HTMLNames.h" 35 #include "core/html/HTMLInputElement.h" 36 #include "core/html/InputTypeNames.h" 37 #include "core/platform/DateComponents.h" 38 #include "wtf/CurrentTime.h" 39 #include "wtf/DateMath.h" 40 #include "wtf/MathExtras.h" 41 #include "wtf/PassOwnPtr.h" 42 43 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) 44 #include "core/html/DateTimeFieldsState.h" 45 #include "core/platform/text/PlatformLocale.h" 46 #include "wtf/text/WTFString.h" 47 #endif 48 49 namespace WebCore { 50 51 using namespace HTMLNames; 52 53 static const int timeDefaultStep = 60; 54 static const int timeDefaultStepBase = 0; 55 static const int timeStepScaleFactor = 1000; 56 57 TimeInputType::TimeInputType(HTMLInputElement* element) 58 : BaseTimeInputType(element) 59 { 60 } 61 62 PassOwnPtr<InputType> TimeInputType::create(HTMLInputElement* element) 63 { 64 return adoptPtr(new TimeInputType(element)); 65 } 66 67 void TimeInputType::attach() 68 { 69 observeFeatureIfVisible(UseCounter::InputTypeTime); 70 } 71 72 const AtomicString& TimeInputType::formControlType() const 73 { 74 return InputTypeNames::time(); 75 } 76 77 DateComponents::Type TimeInputType::dateType() const 78 { 79 return DateComponents::Time; 80 } 81 82 Decimal TimeInputType::defaultValueForStepUp() const 83 { 84 double current = currentTimeMS(); 85 double utcOffset = calculateUTCOffset(); 86 double dstOffset = calculateDSTOffset(current, utcOffset); 87 int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute); 88 current += offset * msPerMinute; 89 90 DateComponents date; 91 date.setMillisecondsSinceMidnight(current); 92 double milliseconds = date.millisecondsSinceEpoch(); 93 ASSERT(std::isfinite(milliseconds)); 94 return Decimal::fromDouble(milliseconds); 95 } 96 97 StepRange TimeInputType::createStepRange(AnyStepHandling anyStepHandling) const 98 { 99 DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (timeDefaultStep, timeDefaultStepBase, timeStepScaleFactor, StepRange::ScaledStepValueShouldBeInteger)); 100 101 const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0); 102 const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumTime())); 103 const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumTime())); 104 const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 105 return StepRange(stepBase, minimum, maximum, step, stepDescription); 106 } 107 108 bool TimeInputType::parseToDateComponentsInternal(const String& string, DateComponents* out) const 109 { 110 ASSERT(out); 111 unsigned end; 112 return out->parseTime(string, 0, end) && end == string.length(); 113 } 114 115 bool TimeInputType::setMillisecondToDateComponents(double value, DateComponents* date) const 116 { 117 ASSERT(date); 118 return date->setMillisecondsSinceMidnight(value); 119 } 120 121 bool TimeInputType::isTimeField() const 122 { 123 return true; 124 } 125 126 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) 127 128 String TimeInputType::localizeValue(const String& proposedValue) const 129 { 130 DateComponents date; 131 if (!parseToDateComponents(proposedValue, &date)) 132 return proposedValue; 133 134 Locale::FormatType formatType = shouldHaveSecondField(date) ? Locale::FormatTypeMedium : Locale::FormatTypeShort; 135 136 String localized = element()->locale().formatDateTime(date, formatType); 137 return localized.isEmpty() ? proposedValue : localized; 138 } 139 140 String TimeInputType::formatDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) const 141 { 142 if (!dateTimeFieldsState.hasHour() || !dateTimeFieldsState.hasMinute() || !dateTimeFieldsState.hasAMPM()) 143 return emptyString(); 144 if (dateTimeFieldsState.hasMillisecond() && dateTimeFieldsState.millisecond()) 145 return String::format("%02u:%02u:%02u.%03u", 146 dateTimeFieldsState.hour23(), 147 dateTimeFieldsState.minute(), 148 dateTimeFieldsState.hasSecond() ? dateTimeFieldsState.second() : 0, 149 dateTimeFieldsState.millisecond()); 150 if (dateTimeFieldsState.hasSecond() && dateTimeFieldsState.second()) 151 return String::format("%02u:%02u:%02u", 152 dateTimeFieldsState.hour23(), 153 dateTimeFieldsState.minute(), 154 dateTimeFieldsState.second()); 155 return String::format("%02u:%02u", dateTimeFieldsState.hour23(), dateTimeFieldsState.minute()); 156 } 157 158 void TimeInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& date) const 159 { 160 if (shouldHaveSecondField(date)) { 161 layoutParameters.dateTimeFormat = layoutParameters.locale.timeFormat(); 162 layoutParameters.fallbackDateTimeFormat = "HH:mm:ss"; 163 } else { 164 layoutParameters.dateTimeFormat = layoutParameters.locale.shortTimeFormat(); 165 layoutParameters.fallbackDateTimeFormat = "HH:mm"; 166 } 167 if (!parseToDateComponents(element()->fastGetAttribute(minAttr), &layoutParameters.minimum)) 168 layoutParameters.minimum = DateComponents(); 169 if (!parseToDateComponents(element()->fastGetAttribute(maxAttr), &layoutParameters.maximum)) 170 layoutParameters.maximum = DateComponents(); 171 } 172 173 bool TimeInputType::isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const 174 { 175 return hasHour && hasMinute && hasAMPM; 176 } 177 #endif 178 179 } // namespace WebCore 180