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/DateTimeLocalInputType.h" 33 34 #include "HTMLNames.h" 35 #include "bindings/v8/ExceptionState.h" 36 #include "core/html/HTMLInputElement.h" 37 #include "core/html/InputTypeNames.h" 38 #include "core/platform/DateComponents.h" 39 #include "wtf/PassOwnPtr.h" 40 41 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) 42 #include "core/html/DateTimeFieldsState.h" 43 #include "core/platform/LocalizedStrings.h" 44 #include "core/platform/text/PlatformLocale.h" 45 #include "wtf/text/WTFString.h" 46 #endif 47 48 namespace WebCore { 49 50 using namespace HTMLNames; 51 52 static const int dateTimeLocalDefaultStep = 60; 53 static const int dateTimeLocalDefaultStepBase = 0; 54 static const int dateTimeLocalStepScaleFactor = 1000; 55 56 PassOwnPtr<InputType> DateTimeLocalInputType::create(HTMLInputElement* element) 57 { 58 return adoptPtr(new DateTimeLocalInputType(element)); 59 } 60 61 void DateTimeLocalInputType::attach() 62 { 63 observeFeatureIfVisible(UseCounter::InputTypeDateTimeLocal); 64 } 65 66 const AtomicString& DateTimeLocalInputType::formControlType() const 67 { 68 return InputTypeNames::datetimelocal(); 69 } 70 71 DateComponents::Type DateTimeLocalInputType::dateType() const 72 { 73 return DateComponents::DateTimeLocal; 74 } 75 76 double DateTimeLocalInputType::valueAsDate() const 77 { 78 // valueAsDate doesn't work for the datetime-local type according to the standard. 79 return DateComponents::invalidMilliseconds(); 80 } 81 82 void DateTimeLocalInputType::setValueAsDate(double value, ExceptionState& es) const 83 { 84 // valueAsDate doesn't work for the datetime-local type according to the standard. 85 InputType::setValueAsDate(value, es); 86 } 87 88 StepRange DateTimeLocalInputType::createStepRange(AnyStepHandling anyStepHandling) const 89 { 90 DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (dateTimeLocalDefaultStep, dateTimeLocalDefaultStepBase, dateTimeLocalStepScaleFactor, StepRange::ScaledStepValueShouldBeInteger)); 91 92 const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0); 93 const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumDateTime())); 94 const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumDateTime())); 95 const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 96 return StepRange(stepBase, minimum, maximum, step, stepDescription); 97 } 98 99 bool DateTimeLocalInputType::parseToDateComponentsInternal(const String& string, DateComponents* out) const 100 { 101 ASSERT(out); 102 unsigned end; 103 return out->parseDateTimeLocal(string, 0, end) && end == string.length(); 104 } 105 106 bool DateTimeLocalInputType::setMillisecondToDateComponents(double value, DateComponents* date) const 107 { 108 ASSERT(date); 109 return date->setMillisecondsSinceEpochForDateTimeLocal(value); 110 } 111 112 bool DateTimeLocalInputType::isDateTimeLocalField() const 113 { 114 return true; 115 } 116 117 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) 118 // FIXME: It is better to share code for DateTimeInputType::formatDateTimeFieldsState() 119 // and DateTimeInputLocalType::formatDateTimeFieldsState(). 120 String DateTimeLocalInputType::formatDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) const 121 { 122 if (!dateTimeFieldsState.hasDayOfMonth() || !dateTimeFieldsState.hasMonth() || !dateTimeFieldsState.hasYear() 123 || !dateTimeFieldsState.hasHour() || !dateTimeFieldsState.hasMinute() || !dateTimeFieldsState.hasAMPM()) 124 return emptyString(); 125 126 if (dateTimeFieldsState.hasMillisecond() && dateTimeFieldsState.millisecond()) { 127 return String::format("%04u-%02u-%02uT%02u:%02u:%02u.%03u", 128 dateTimeFieldsState.year(), 129 dateTimeFieldsState.month(), 130 dateTimeFieldsState.dayOfMonth(), 131 dateTimeFieldsState.hour23(), 132 dateTimeFieldsState.minute(), 133 dateTimeFieldsState.hasSecond() ? dateTimeFieldsState.second() : 0, 134 dateTimeFieldsState.millisecond()); 135 } 136 137 if (dateTimeFieldsState.hasSecond() && dateTimeFieldsState.second()) { 138 return String::format("%04u-%02u-%02uT%02u:%02u:%02u", 139 dateTimeFieldsState.year(), 140 dateTimeFieldsState.month(), 141 dateTimeFieldsState.dayOfMonth(), 142 dateTimeFieldsState.hour23(), 143 dateTimeFieldsState.minute(), 144 dateTimeFieldsState.second()); 145 } 146 147 return String::format("%04u-%02u-%02uT%02u:%02u", 148 dateTimeFieldsState.year(), 149 dateTimeFieldsState.month(), 150 dateTimeFieldsState.dayOfMonth(), 151 dateTimeFieldsState.hour23(), 152 dateTimeFieldsState.minute()); 153 } 154 155 void DateTimeLocalInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& date) const 156 { 157 if (shouldHaveSecondField(date)) { 158 layoutParameters.dateTimeFormat = layoutParameters.locale.dateTimeFormatWithSeconds(); 159 layoutParameters.fallbackDateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss"; 160 } else { 161 layoutParameters.dateTimeFormat = layoutParameters.locale.dateTimeFormatWithoutSeconds(); 162 layoutParameters.fallbackDateTimeFormat = "yyyy-MM-dd'T'HH:mm"; 163 } 164 if (!parseToDateComponents(element()->fastGetAttribute(minAttr), &layoutParameters.minimum)) 165 layoutParameters.minimum = DateComponents(); 166 if (!parseToDateComponents(element()->fastGetAttribute(maxAttr), &layoutParameters.maximum)) 167 layoutParameters.maximum = DateComponents(); 168 layoutParameters.placeholderForDay = placeholderForDayOfMonthField(); 169 layoutParameters.placeholderForMonth = placeholderForMonthField(); 170 layoutParameters.placeholderForYear = placeholderForYearField(); 171 } 172 173 bool DateTimeLocalInputType::isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const 174 { 175 return hasYear && hasMonth && hasDay && hasAMPM && hasHour && hasMinute; 176 } 177 #endif 178 179 } // namespace WebCore 180