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 "BaseDateAndTimeInputType.h" 33 34 #include "DateComponents.h" 35 #include "HTMLInputElement.h" 36 #include "HTMLNames.h" 37 #include "KeyboardEvent.h" 38 #include <limits> 39 #include <wtf/CurrentTime.h> 40 #include <wtf/DateMath.h> 41 #include <wtf/MathExtras.h> 42 #include <wtf/PassOwnPtr.h> 43 #include <wtf/text/WTFString.h> 44 45 namespace WebCore { 46 47 using namespace HTMLNames; 48 using namespace std; 49 50 static const double msecPerMinute = 60 * 1000; 51 static const double msecPerSecond = 1000; 52 53 double BaseDateAndTimeInputType::valueAsDate() const 54 { 55 return parseToDouble(element()->value(), DateComponents::invalidMilliseconds()); 56 } 57 58 void BaseDateAndTimeInputType::setValueAsDate(double value, ExceptionCode&) const 59 { 60 element()->setValue(serialize(value)); 61 } 62 63 double BaseDateAndTimeInputType::valueAsNumber() const 64 { 65 return parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN()); 66 } 67 68 void BaseDateAndTimeInputType::setValueAsNumber(double newValue, ExceptionCode&) const 69 { 70 element()->setValue(serialize(newValue)); 71 } 72 73 bool BaseDateAndTimeInputType::typeMismatchFor(const String& value) const 74 { 75 return !value.isEmpty() && !parseToDateComponents(value, 0); 76 } 77 78 bool BaseDateAndTimeInputType::typeMismatch() const 79 { 80 return typeMismatchFor(element()->value()); 81 } 82 83 bool BaseDateAndTimeInputType::rangeUnderflow(const String& value) const 84 { 85 const double nan = numeric_limits<double>::quiet_NaN(); 86 double doubleValue = parseToDouble(value, nan); 87 return isfinite(doubleValue) && doubleValue < minimum(); 88 } 89 90 bool BaseDateAndTimeInputType::rangeOverflow(const String& value) const 91 { 92 const double nan = numeric_limits<double>::quiet_NaN(); 93 double doubleValue = parseToDouble(value, nan); 94 return isfinite(doubleValue) && doubleValue > maximum(); 95 } 96 97 bool BaseDateAndTimeInputType::supportsRangeLimitation() const 98 { 99 return true; 100 } 101 102 double BaseDateAndTimeInputType::defaultValueForStepUp() const 103 { 104 double ms = currentTimeMS(); 105 double utcOffset = calculateUTCOffset(); 106 double dstOffset = calculateDSTOffset(ms, utcOffset); 107 int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute); 108 return ms + (offset * msPerMinute); 109 } 110 111 bool BaseDateAndTimeInputType::stepMismatch(const String& value, double step) const 112 { 113 const double nan = numeric_limits<double>::quiet_NaN(); 114 double doubleValue = parseToDouble(value, nan); 115 doubleValue = fabs(doubleValue - stepBase()); 116 if (!isfinite(doubleValue)) 117 return false; 118 ASSERT(round(doubleValue) == doubleValue); 119 ASSERT(round(step) == step); 120 return fmod(doubleValue, step); 121 } 122 123 double BaseDateAndTimeInputType::stepBase() const 124 { 125 return parseToDouble(element()->fastGetAttribute(minAttr), defaultStepBase()); 126 } 127 128 void BaseDateAndTimeInputType::handleKeydownEvent(KeyboardEvent* event) 129 { 130 handleKeydownEventForSpinButton(event); 131 if (!event->defaultHandled()) 132 TextFieldInputType::handleKeydownEvent(event); 133 } 134 135 void BaseDateAndTimeInputType::handleWheelEvent(WheelEvent* event) 136 { 137 handleWheelEventForSpinButton(event); 138 } 139 140 double BaseDateAndTimeInputType::parseToDouble(const String& src, double defaultValue) const 141 { 142 DateComponents date; 143 if (!parseToDateComponents(src, &date)) 144 return defaultValue; 145 double msec = date.millisecondsSinceEpoch(); 146 ASSERT(isfinite(msec)); 147 return msec; 148 } 149 150 bool BaseDateAndTimeInputType::parseToDateComponents(const String& source, DateComponents* out) const 151 { 152 if (source.isEmpty()) 153 return false; 154 DateComponents ignoredResult; 155 if (!out) 156 out = &ignoredResult; 157 return parseToDateComponentsInternal(source.characters(), source.length(), out); 158 } 159 160 String BaseDateAndTimeInputType::serialize(double value) const 161 { 162 if (!isfinite(value)) 163 return String(); 164 DateComponents date; 165 if (!setMillisecondToDateComponents(value, &date)) 166 return String(); 167 double step; 168 if (!element()->getAllowedValueStep(&step)) 169 return date.toString(); 170 if (!fmod(step, msecPerMinute)) 171 return date.toString(DateComponents::None); 172 if (!fmod(step, msecPerSecond)) 173 return date.toString(DateComponents::Second); 174 return date.toString(DateComponents::Millisecond); 175 } 176 177 bool BaseDateAndTimeInputType::hasSpinButton() 178 { 179 return true; 180 } 181 182 } // namespace WebCore 183