• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
28 #include "core/html/shadow/DateTimeFieldElements.h"
29 
30 #include "core/html/forms/DateTimeFieldsState.h"
31 #include "platform/DateComponents.h"
32 #include "platform/text/PlatformLocale.h"
33 #include "wtf/CurrentTime.h"
34 #include "wtf/DateMath.h"
35 
36 namespace WebCore {
37 
38 using blink::WebLocalizedString;
39 
queryString(WebLocalizedString::Name name)40 static String queryString(WebLocalizedString::Name name)
41 {
42     return Locale::defaultLocale().queryString(name);
43 }
44 
DateTimeAMPMFieldElement(Document & document,FieldOwner & fieldOwner,const Vector<String> & ampmLabels)45 DateTimeAMPMFieldElement::DateTimeAMPMFieldElement(Document& document, FieldOwner& fieldOwner, const Vector<String>& ampmLabels)
46     : DateTimeSymbolicFieldElement(document, fieldOwner, ampmLabels, 0, 1)
47 {
48 }
49 
create(Document & document,FieldOwner & fieldOwner,const Vector<String> & ampmLabels)50 PassRefPtr<DateTimeAMPMFieldElement> DateTimeAMPMFieldElement::create(Document& document, FieldOwner& fieldOwner, const Vector<String>& ampmLabels)
51 {
52     DEFINE_STATIC_LOCAL(AtomicString, ampmPsuedoId, ("-webkit-datetime-edit-ampm-field", AtomicString::ConstructFromLiteral));
53     RefPtr<DateTimeAMPMFieldElement> field = adoptRef(new DateTimeAMPMFieldElement(document, fieldOwner, ampmLabels));
54     field->initialize(ampmPsuedoId, queryString(WebLocalizedString::AXAMPMFieldText));
55     return field.release();
56 }
57 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)58 void DateTimeAMPMFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
59 {
60     if (hasValue())
61         dateTimeFieldsState.setAMPM(valueAsInteger() ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM);
62     else
63         dateTimeFieldsState.setAMPM(DateTimeFieldsState::AMPMValueEmpty);
64 }
65 
setValueAsDate(const DateComponents & date)66 void DateTimeAMPMFieldElement::setValueAsDate(const DateComponents& date)
67 {
68     setValueAsInteger(date.hour() >= 12 ? 1 : 0);
69 }
70 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)71 void DateTimeAMPMFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
72 {
73     if (dateTimeFieldsState.hasAMPM())
74         setValueAsInteger(dateTimeFieldsState.ampm());
75     else
76         setEmptyValue();
77 }
78 
79 // ----------------------------
80 
DateTimeDayFieldElement(Document & document,FieldOwner & fieldOwner,const String & placeholder,const Range & range)81 DateTimeDayFieldElement::DateTimeDayFieldElement(Document& document, FieldOwner& fieldOwner, const String& placeholder, const Range& range)
82     : DateTimeNumericFieldElement(document, fieldOwner, range, Range(1, 31), placeholder)
83 {
84 }
85 
create(Document & document,FieldOwner & fieldOwner,const String & placeholder,const Range & range)86 PassRefPtr<DateTimeDayFieldElement> DateTimeDayFieldElement::create(Document& document, FieldOwner& fieldOwner, const String& placeholder, const Range& range)
87 {
88     DEFINE_STATIC_LOCAL(AtomicString, dayPsuedoId, ("-webkit-datetime-edit-day-field", AtomicString::ConstructFromLiteral));
89     RefPtr<DateTimeDayFieldElement> field = adoptRef(new DateTimeDayFieldElement(document, fieldOwner, placeholder.isEmpty() ? "--" : placeholder, range));
90     field->initialize(dayPsuedoId, queryString(WebLocalizedString::AXDayOfMonthFieldText));
91     return field.release();
92 }
93 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)94 void DateTimeDayFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
95 {
96     dateTimeFieldsState.setDayOfMonth(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
97 }
98 
setValueAsDate(const DateComponents & date)99 void DateTimeDayFieldElement::setValueAsDate(const DateComponents& date)
100 {
101     setValueAsInteger(date.monthDay());
102 }
103 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)104 void DateTimeDayFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
105 {
106     if (!dateTimeFieldsState.hasDayOfMonth()) {
107         setEmptyValue();
108         return;
109     }
110 
111     const unsigned value = dateTimeFieldsState.dayOfMonth();
112     if (range().isInRange(static_cast<int>(value))) {
113         setValueAsInteger(value);
114         return;
115     }
116 
117     setEmptyValue();
118 }
119 
120 // ----------------------------
121 
DateTimeHourFieldElementBase(Document & document,FieldOwner & fieldOwner,const Range & range,const Range & hardLimits,const Step & step)122 DateTimeHourFieldElementBase::DateTimeHourFieldElementBase(Document& document, FieldOwner& fieldOwner, const Range& range, const Range& hardLimits, const Step& step)
123     : DateTimeNumericFieldElement(document, fieldOwner, range, hardLimits, "--", step)
124 {
125 }
126 
initialize()127 void DateTimeHourFieldElementBase::initialize()
128 {
129     DEFINE_STATIC_LOCAL(AtomicString, hourPsuedoId, ("-webkit-datetime-edit-hour-field", AtomicString::ConstructFromLiteral));
130     DateTimeNumericFieldElement::initialize(hourPsuedoId, queryString(WebLocalizedString::AXHourFieldText));
131 }
132 
setValueAsDate(const DateComponents & date)133 void DateTimeHourFieldElementBase::setValueAsDate(const DateComponents& date)
134 {
135     setValueAsInteger(date.hour());
136 }
137 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)138 void DateTimeHourFieldElementBase::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
139 {
140     if (!dateTimeFieldsState.hasHour()) {
141         setEmptyValue();
142         return;
143     }
144 
145     const int hour12 = dateTimeFieldsState.hour();
146     if (hour12 < 1 || hour12 > 12) {
147         setEmptyValue();
148         return;
149     }
150 
151     const int hour11 = hour12 == 12 ? 0 : hour12;
152     const int hour23 = dateTimeFieldsState.ampm() == DateTimeFieldsState::AMPMValuePM ? hour11 + 12 : hour11;
153     setValueAsInteger(hour23);
154 }
155 // ----------------------------
156 
DateTimeHour11FieldElement(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)157 DateTimeHour11FieldElement::DateTimeHour11FieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
158     : DateTimeHourFieldElementBase(document, fieldOwner, range, Range(0, 11), step)
159 {
160 }
161 
create(Document & document,FieldOwner & fieldOwner,const Range & hour23Range,const Step & step)162 PassRefPtr<DateTimeHour11FieldElement> DateTimeHour11FieldElement::create(Document& document, FieldOwner& fieldOwner, const Range& hour23Range, const Step& step)
163 {
164     ASSERT(hour23Range.minimum >= 0);
165     ASSERT(hour23Range.maximum <= 23);
166     ASSERT(hour23Range.minimum <= hour23Range.maximum);
167     Range range(0, 11);
168     if (hour23Range.maximum < 12)
169         range = hour23Range;
170     else if (hour23Range.minimum >= 12) {
171         range.minimum = hour23Range.minimum - 12;
172         range.maximum = hour23Range.maximum - 12;
173     }
174 
175     RefPtr<DateTimeHour11FieldElement> field = adoptRef(new DateTimeHour11FieldElement(document, fieldOwner, range, step));
176     field->initialize();
177     return field.release();
178 }
179 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)180 void DateTimeHour11FieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
181 {
182     if (!hasValue()) {
183         dateTimeFieldsState.setHour(DateTimeFieldsState::emptyValue);
184         return;
185     }
186     const int value = valueAsInteger();
187     dateTimeFieldsState.setHour(value ? value : 12);
188 }
189 
setValueAsInteger(int value,EventBehavior eventBehavior)190 void DateTimeHour11FieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
191 {
192     value = Range(0, 23).clampValue(value) % 12;
193     DateTimeNumericFieldElement::setValueAsInteger(value, eventBehavior);
194 }
195 
196 // ----------------------------
197 
DateTimeHour12FieldElement(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)198 DateTimeHour12FieldElement::DateTimeHour12FieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
199     : DateTimeHourFieldElementBase(document, fieldOwner, range, Range(1, 12), step)
200 {
201 }
202 
create(Document & document,FieldOwner & fieldOwner,const Range & hour23Range,const Step & step)203 PassRefPtr<DateTimeHour12FieldElement> DateTimeHour12FieldElement::create(Document& document, FieldOwner& fieldOwner, const Range& hour23Range, const Step& step)
204 {
205     ASSERT(hour23Range.minimum >= 0);
206     ASSERT(hour23Range.maximum <= 23);
207     ASSERT(hour23Range.minimum <= hour23Range.maximum);
208     Range range(1, 12);
209     if (hour23Range.maximum < 12)
210         range = hour23Range;
211     else if (hour23Range.minimum >= 12) {
212         range.minimum = hour23Range.minimum - 12;
213         range.maximum = hour23Range.maximum - 12;
214     }
215     if (!range.minimum)
216         range.minimum = 12;
217     if (!range.maximum)
218         range.maximum = 12;
219     if (range.minimum > range.maximum) {
220         range.minimum = 1;
221         range.maximum = 12;
222     }
223     RefPtr<DateTimeHour12FieldElement> field = adoptRef(new DateTimeHour12FieldElement(document, fieldOwner, range, step));
224     field->initialize();
225     return field.release();
226 }
227 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)228 void DateTimeHour12FieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
229 {
230     dateTimeFieldsState.setHour(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
231 }
232 
setValueAsInteger(int value,EventBehavior eventBehavior)233 void DateTimeHour12FieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
234 {
235     value = Range(0, 24).clampValue(value) % 12;
236     DateTimeNumericFieldElement::setValueAsInteger(value ? value : 12, eventBehavior);
237 }
238 
239 // ----------------------------
240 
DateTimeHour23FieldElement(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)241 DateTimeHour23FieldElement::DateTimeHour23FieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
242     : DateTimeHourFieldElementBase(document, fieldOwner, range, Range(0, 23), step)
243 {
244 }
245 
create(Document & document,FieldOwner & fieldOwner,const Range & hour23Range,const Step & step)246 PassRefPtr<DateTimeHour23FieldElement> DateTimeHour23FieldElement::create(Document& document, FieldOwner& fieldOwner, const Range& hour23Range, const Step& step)
247 {
248     ASSERT(hour23Range.minimum >= 0);
249     ASSERT(hour23Range.maximum <= 23);
250     ASSERT(hour23Range.minimum <= hour23Range.maximum);
251     RefPtr<DateTimeHour23FieldElement> field = adoptRef(new DateTimeHour23FieldElement(document, fieldOwner, hour23Range, step));
252     field->initialize();
253     return field.release();
254 }
255 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)256 void DateTimeHour23FieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
257 {
258     if (!hasValue()) {
259         dateTimeFieldsState.setHour(DateTimeFieldsState::emptyValue);
260         return;
261     }
262 
263     const int value = valueAsInteger();
264 
265     dateTimeFieldsState.setHour(value % 12 ? value % 12 : 12);
266     dateTimeFieldsState.setAMPM(value >= 12 ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM);
267 }
268 
setValueAsInteger(int value,EventBehavior eventBehavior)269 void DateTimeHour23FieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
270 {
271     value = Range(0, 23).clampValue(value);
272     DateTimeNumericFieldElement::setValueAsInteger(value, eventBehavior);
273 }
274 
275 // ----------------------------
276 
DateTimeHour24FieldElement(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)277 DateTimeHour24FieldElement::DateTimeHour24FieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
278     : DateTimeHourFieldElementBase(document, fieldOwner, range, Range(1, 24), step)
279 {
280 }
281 
create(Document & document,FieldOwner & fieldOwner,const Range & hour23Range,const Step & step)282 PassRefPtr<DateTimeHour24FieldElement> DateTimeHour24FieldElement::create(Document& document, FieldOwner& fieldOwner, const Range& hour23Range, const Step& step)
283 {
284     ASSERT(hour23Range.minimum >= 0);
285     ASSERT(hour23Range.maximum <= 23);
286     ASSERT(hour23Range.minimum <= hour23Range.maximum);
287     Range range(hour23Range.minimum ? hour23Range.minimum : 24, hour23Range.maximum ? hour23Range.maximum : 24);
288     if (range.minimum > range.maximum) {
289         range.minimum = 1;
290         range.maximum = 24;
291     }
292 
293     RefPtr<DateTimeHour24FieldElement> field = adoptRef(new DateTimeHour24FieldElement(document, fieldOwner, range, step));
294     field->initialize();
295     return field.release();
296 }
297 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)298 void DateTimeHour24FieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
299 {
300     if (!hasValue()) {
301         dateTimeFieldsState.setHour(DateTimeFieldsState::emptyValue);
302         return;
303     }
304 
305     const int value = valueAsInteger();
306 
307     if (value == 24) {
308         dateTimeFieldsState.setHour(12);
309         dateTimeFieldsState.setAMPM(DateTimeFieldsState::AMPMValueAM);
310     } else {
311         dateTimeFieldsState.setHour(value == 12 ? 12 : value % 12);
312         dateTimeFieldsState.setAMPM(value >= 12 ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM);
313     }
314 }
315 
setValueAsInteger(int value,EventBehavior eventBehavior)316 void DateTimeHour24FieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
317 {
318     value = Range(0, 24).clampValue(value);
319     DateTimeNumericFieldElement::setValueAsInteger(value ? value : 24, eventBehavior);
320 }
321 
322 // ----------------------------
323 
DateTimeMillisecondFieldElement(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)324 DateTimeMillisecondFieldElement::DateTimeMillisecondFieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
325     : DateTimeNumericFieldElement(document, fieldOwner, range, Range(0, 999), "---", step)
326 {
327 }
328 
create(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)329 PassRefPtr<DateTimeMillisecondFieldElement> DateTimeMillisecondFieldElement::create(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
330 {
331     DEFINE_STATIC_LOCAL(AtomicString, millisecondPsuedoId, ("-webkit-datetime-edit-millisecond-field", AtomicString::ConstructFromLiteral));
332     RefPtr<DateTimeMillisecondFieldElement> field = adoptRef(new DateTimeMillisecondFieldElement(document, fieldOwner, range, step));
333     field->initialize(millisecondPsuedoId, queryString(WebLocalizedString::AXMillisecondFieldText));
334     return field.release();
335 }
336 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)337 void DateTimeMillisecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
338 {
339     dateTimeFieldsState.setMillisecond(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
340 }
341 
setValueAsDate(const DateComponents & date)342 void DateTimeMillisecondFieldElement::setValueAsDate(const DateComponents& date)
343 {
344     setValueAsInteger(date.millisecond());
345 }
346 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)347 void DateTimeMillisecondFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
348 {
349     if (!dateTimeFieldsState.hasMillisecond()) {
350         setEmptyValue();
351         return;
352     }
353 
354     const unsigned value = dateTimeFieldsState.millisecond();
355     if (value > static_cast<unsigned>(maximum())) {
356         setEmptyValue();
357         return;
358     }
359 
360     setValueAsInteger(value);
361 }
362 
363 // ----------------------------
364 
DateTimeMinuteFieldElement(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)365 DateTimeMinuteFieldElement::DateTimeMinuteFieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
366     : DateTimeNumericFieldElement(document, fieldOwner, range, Range(0, 59), "--", step)
367 {
368 }
369 
create(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)370 PassRefPtr<DateTimeMinuteFieldElement> DateTimeMinuteFieldElement::create(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
371 {
372     DEFINE_STATIC_LOCAL(AtomicString, minutePsuedoId, ("-webkit-datetime-edit-minute-field", AtomicString::ConstructFromLiteral));
373     RefPtr<DateTimeMinuteFieldElement> field = adoptRef(new DateTimeMinuteFieldElement(document, fieldOwner, range, step));
374     field->initialize(minutePsuedoId, queryString(WebLocalizedString::AXMinuteFieldText));
375     return field.release();
376 }
377 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)378 void DateTimeMinuteFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
379 {
380     dateTimeFieldsState.setMinute(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
381 }
382 
setValueAsDate(const DateComponents & date)383 void DateTimeMinuteFieldElement::setValueAsDate(const DateComponents& date)
384 {
385     setValueAsInteger(date.minute());
386 }
387 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)388 void DateTimeMinuteFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
389 {
390     if (!dateTimeFieldsState.hasMinute()) {
391         setEmptyValue();
392         return;
393     }
394 
395     const unsigned value = dateTimeFieldsState.minute();
396     if (value > static_cast<unsigned>(maximum())) {
397         setEmptyValue();
398         return;
399     }
400 
401     setValueAsInteger(value);
402 }
403 
404 // ----------------------------
405 
DateTimeMonthFieldElement(Document & document,FieldOwner & fieldOwner,const String & placeholder,const Range & range)406 DateTimeMonthFieldElement::DateTimeMonthFieldElement(Document& document, FieldOwner& fieldOwner, const String& placeholder, const Range& range)
407     : DateTimeNumericFieldElement(document, fieldOwner, range, Range(1, 12), placeholder)
408 {
409 }
410 
create(Document & document,FieldOwner & fieldOwner,const String & placeholder,const Range & range)411 PassRefPtr<DateTimeMonthFieldElement> DateTimeMonthFieldElement::create(Document& document, FieldOwner& fieldOwner, const String& placeholder, const Range& range)
412 {
413     DEFINE_STATIC_LOCAL(AtomicString, monthPsuedoId, ("-webkit-datetime-edit-month-field", AtomicString::ConstructFromLiteral));
414     RefPtr<DateTimeMonthFieldElement> field = adoptRef(new DateTimeMonthFieldElement(document, fieldOwner, placeholder.isEmpty() ? "--" : placeholder, range));
415     field->initialize(monthPsuedoId, queryString(WebLocalizedString::AXMonthFieldText));
416     return field.release();
417 }
418 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)419 void DateTimeMonthFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
420 {
421     dateTimeFieldsState.setMonth(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
422 }
423 
setValueAsDate(const DateComponents & date)424 void DateTimeMonthFieldElement::setValueAsDate(const DateComponents& date)
425 {
426     setValueAsInteger(date.month() + 1);
427 }
428 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)429 void DateTimeMonthFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
430 {
431     if (!dateTimeFieldsState.hasMonth()) {
432         setEmptyValue();
433         return;
434     }
435 
436     const unsigned value = dateTimeFieldsState.month();
437     if (range().isInRange(static_cast<int>(value))) {
438         setValueAsInteger(value);
439         return;
440     }
441 
442     setEmptyValue();
443 }
444 
445 // ----------------------------
446 
DateTimeSecondFieldElement(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)447 DateTimeSecondFieldElement::DateTimeSecondFieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
448     : DateTimeNumericFieldElement(document, fieldOwner, range, Range(0, 59), "--", step)
449 {
450 }
451 
create(Document & document,FieldOwner & fieldOwner,const Range & range,const Step & step)452 PassRefPtr<DateTimeSecondFieldElement> DateTimeSecondFieldElement::create(Document& document, FieldOwner& fieldOwner, const Range& range, const Step& step)
453 {
454     DEFINE_STATIC_LOCAL(AtomicString, secondPsuedoId, ("-webkit-datetime-edit-second-field", AtomicString::ConstructFromLiteral));
455     RefPtr<DateTimeSecondFieldElement> field = adoptRef(new DateTimeSecondFieldElement(document, fieldOwner, range, step));
456     field->initialize(secondPsuedoId, queryString(WebLocalizedString::AXSecondFieldText));
457     return field.release();
458 }
459 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)460 void DateTimeSecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
461 {
462     dateTimeFieldsState.setSecond(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
463 }
464 
setValueAsDate(const DateComponents & date)465 void DateTimeSecondFieldElement::setValueAsDate(const DateComponents& date)
466 {
467     setValueAsInteger(date.second());
468 }
469 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)470 void DateTimeSecondFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
471 {
472     if (!dateTimeFieldsState.hasSecond()) {
473         setEmptyValue();
474         return;
475     }
476 
477     const unsigned value = dateTimeFieldsState.second();
478     if (value > static_cast<unsigned>(maximum())) {
479         setEmptyValue();
480         return;
481     }
482 
483     setValueAsInteger(value);
484 }
485 
486 // ----------------------------
487 
DateTimeSymbolicMonthFieldElement(Document & document,FieldOwner & fieldOwner,const Vector<String> & labels,int minimum,int maximum)488 DateTimeSymbolicMonthFieldElement::DateTimeSymbolicMonthFieldElement(Document& document, FieldOwner& fieldOwner, const Vector<String>& labels, int minimum, int maximum)
489     : DateTimeSymbolicFieldElement(document, fieldOwner, labels, minimum, maximum)
490 {
491 }
492 
create(Document & document,FieldOwner & fieldOwner,const Vector<String> & labels,int minimum,int maximum)493 PassRefPtr<DateTimeSymbolicMonthFieldElement> DateTimeSymbolicMonthFieldElement::create(Document& document, FieldOwner& fieldOwner, const Vector<String>& labels, int minimum, int maximum)
494 {
495     DEFINE_STATIC_LOCAL(AtomicString, monthPsuedoId, ("-webkit-datetime-edit-month-field", AtomicString::ConstructFromLiteral));
496     RefPtr<DateTimeSymbolicMonthFieldElement> field = adoptRef(new DateTimeSymbolicMonthFieldElement(document, fieldOwner, labels, minimum, maximum));
497     field->initialize(monthPsuedoId, queryString(WebLocalizedString::AXMonthFieldText));
498     return field.release();
499 }
500 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)501 void DateTimeSymbolicMonthFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
502 {
503     if (!hasValue())
504         dateTimeFieldsState.setMonth(DateTimeFieldsState::emptyValue);
505     ASSERT(valueAsInteger() < static_cast<int>(symbolsSize()));
506     dateTimeFieldsState.setMonth(valueAsInteger() + 1);
507 }
508 
setValueAsDate(const DateComponents & date)509 void DateTimeSymbolicMonthFieldElement::setValueAsDate(const DateComponents& date)
510 {
511     setValueAsInteger(date.month());
512 }
513 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)514 void DateTimeSymbolicMonthFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
515 {
516     if (!dateTimeFieldsState.hasMonth()) {
517         setEmptyValue();
518         return;
519     }
520 
521     const unsigned value = dateTimeFieldsState.month() - 1;
522     if (value >= symbolsSize()) {
523         setEmptyValue();
524         return;
525     }
526 
527     setValueAsInteger(value);
528 }
529 
530 // ----------------------------
531 
DateTimeWeekFieldElement(Document & document,FieldOwner & fieldOwner,const Range & range)532 DateTimeWeekFieldElement::DateTimeWeekFieldElement(Document& document, FieldOwner& fieldOwner, const Range& range)
533     : DateTimeNumericFieldElement(document, fieldOwner, range, Range(DateComponents::minimumWeekNumber, DateComponents::maximumWeekNumber), "--")
534 {
535 }
536 
create(Document & document,FieldOwner & fieldOwner,const Range & range)537 PassRefPtr<DateTimeWeekFieldElement> DateTimeWeekFieldElement::create(Document& document, FieldOwner& fieldOwner, const Range& range)
538 {
539     DEFINE_STATIC_LOCAL(AtomicString, weekPsuedoId, ("-webkit-datetime-edit-week-field", AtomicString::ConstructFromLiteral));
540     RefPtr<DateTimeWeekFieldElement> field = adoptRef(new DateTimeWeekFieldElement(document, fieldOwner, range));
541     field->initialize(weekPsuedoId, queryString(WebLocalizedString::AXWeekOfYearFieldText));
542     return field.release();
543 }
544 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)545 void DateTimeWeekFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
546 {
547     dateTimeFieldsState.setWeekOfYear(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
548 }
549 
setValueAsDate(const DateComponents & date)550 void DateTimeWeekFieldElement::setValueAsDate(const DateComponents& date)
551 {
552     setValueAsInteger(date.week());
553 }
554 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)555 void DateTimeWeekFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
556 {
557     if (!dateTimeFieldsState.hasWeekOfYear()) {
558         setEmptyValue();
559         return;
560     }
561 
562     const unsigned value = dateTimeFieldsState.weekOfYear();
563     if (range().isInRange(static_cast<int>(value))) {
564         setValueAsInteger(value);
565         return;
566     }
567 
568     setEmptyValue();
569 }
570 
571 // ----------------------------
572 
DateTimeYearFieldElement(Document & document,FieldOwner & fieldOwner,const DateTimeYearFieldElement::Parameters & parameters)573 DateTimeYearFieldElement::DateTimeYearFieldElement(Document& document, FieldOwner& fieldOwner, const DateTimeYearFieldElement::Parameters& parameters)
574     : DateTimeNumericFieldElement(document, fieldOwner, Range(parameters.minimumYear, parameters.maximumYear), Range(DateComponents::minimumYear(), DateComponents::maximumYear()), parameters.placeholder.isEmpty() ? "----" : parameters.placeholder)
575     , m_minIsSpecified(parameters.minIsSpecified)
576     , m_maxIsSpecified(parameters.maxIsSpecified)
577 {
578     ASSERT(parameters.minimumYear >= DateComponents::minimumYear());
579     ASSERT(parameters.maximumYear <= DateComponents::maximumYear());
580 }
581 
create(Document & document,FieldOwner & fieldOwner,const DateTimeYearFieldElement::Parameters & parameters)582 PassRefPtr<DateTimeYearFieldElement> DateTimeYearFieldElement::create(Document& document, FieldOwner& fieldOwner, const DateTimeYearFieldElement::Parameters& parameters)
583 {
584     DEFINE_STATIC_LOCAL(AtomicString, yearPsuedoId, ("-webkit-datetime-edit-year-field", AtomicString::ConstructFromLiteral));
585     RefPtr<DateTimeYearFieldElement> field = adoptRef(new DateTimeYearFieldElement(document, fieldOwner, parameters));
586     field->initialize(yearPsuedoId, queryString(WebLocalizedString::AXYearFieldText));
587     return field.release();
588 }
589 
currentFullYear()590 static int currentFullYear()
591 {
592     double current = currentTimeMS();
593     double utcOffset = calculateUTCOffset();
594     double dstOffset = calculateDSTOffset(current, utcOffset);
595     int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
596     current += offset * msPerMinute;
597 
598     DateComponents date;
599     date.setMillisecondsSinceEpochForMonth(current);
600     return date.fullYear();
601 }
602 
defaultValueForStepDown() const603 int DateTimeYearFieldElement::defaultValueForStepDown() const
604 {
605     return m_maxIsSpecified ? DateTimeNumericFieldElement::defaultValueForStepDown() : currentFullYear();
606 }
607 
defaultValueForStepUp() const608 int DateTimeYearFieldElement::defaultValueForStepUp() const
609 {
610     return m_minIsSpecified ? DateTimeNumericFieldElement::defaultValueForStepUp() : currentFullYear();
611 }
612 
populateDateTimeFieldsState(DateTimeFieldsState & dateTimeFieldsState)613 void DateTimeYearFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
614 {
615     dateTimeFieldsState.setYear(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
616 }
617 
setValueAsDate(const DateComponents & date)618 void DateTimeYearFieldElement::setValueAsDate(const DateComponents& date)
619 {
620     setValueAsInteger(date.fullYear());
621 }
622 
setValueAsDateTimeFieldsState(const DateTimeFieldsState & dateTimeFieldsState)623 void DateTimeYearFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
624 {
625     if (!dateTimeFieldsState.hasYear()) {
626         setEmptyValue();
627         return;
628     }
629 
630     const unsigned value = dateTimeFieldsState.year();
631     if (range().isInRange(static_cast<int>(value))) {
632         setValueAsInteger(value);
633         return;
634     }
635 
636     setEmptyValue();
637 }
638 
639 } // namespace WebCore
640 
641 #endif
642