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