Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp

Issue 2815263002: Move form-related files in core/html/shadow to core/html/forms. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "core/html/shadow/DateTimeEditElement.h"
27
28 #include "bindings/core/v8/ExceptionState.h"
29 #include "core/HTMLNames.h"
30 #include "core/dom/Document.h"
31 #include "core/dom/StyleChangeReason.h"
32 #include "core/dom/Text.h"
33 #include "core/events/MouseEvent.h"
34 #include "core/html/forms/DateTimeFieldsState.h"
35 #include "core/html/shadow/DateTimeFieldElements.h"
36 #include "core/html/shadow/ShadowElementNames.h"
37 #include "core/style/ComputedStyle.h"
38 #include "core/style/StyleInheritedData.h"
39 #include "platform/fonts/FontCache.h"
40 #include "platform/text/DateTimeFormat.h"
41 #include "platform/text/PlatformLocale.h"
42 #include "platform/wtf/DateMath.h"
43
44 namespace blink {
45
46 using namespace HTMLNames;
47 using namespace WTF::Unicode;
48
49 class DateTimeEditBuilder : private DateTimeFormat::TokenHandler {
50 public:
51 // The argument objects must be alive until this object dies.
52 DateTimeEditBuilder(DateTimeEditElement&,
53 const DateTimeEditElement::LayoutParameters&,
54 const DateComponents&);
55
56 bool Build(const String&);
57
58 private:
59 bool NeedMillisecondField() const;
60 bool ShouldAMPMFieldDisabled() const;
61 bool ShouldDayOfMonthFieldDisabled() const;
62 bool ShouldHourFieldDisabled() const;
63 bool ShouldMillisecondFieldDisabled() const;
64 bool ShouldMinuteFieldDisabled() const;
65 bool ShouldSecondFieldDisabled() const;
66 bool ShouldYearFieldDisabled() const;
67 inline const StepRange& GetStepRange() const {
68 return parameters_.step_range;
69 }
70 DateTimeNumericFieldElement::Step CreateStep(double ms_per_field_unit,
71 double ms_per_field_size) const;
72
73 // DateTimeFormat::TokenHandler functions.
74 void VisitField(DateTimeFormat::FieldType, int) final;
75 void VisitLiteral(const String&) final;
76
77 DateTimeEditElement& EditElement() const;
78
79 Member<DateTimeEditElement> edit_element_;
80 const DateComponents date_value_;
81 const DateTimeEditElement::LayoutParameters& parameters_;
82 DateTimeNumericFieldElement::Range day_range_;
83 DateTimeNumericFieldElement::Range hour23_range_;
84 DateTimeNumericFieldElement::Range minute_range_;
85 DateTimeNumericFieldElement::Range second_range_;
86 DateTimeNumericFieldElement::Range millisecond_range_;
87 };
88
89 DateTimeEditBuilder::DateTimeEditBuilder(
90 DateTimeEditElement& element,
91 const DateTimeEditElement::LayoutParameters& layout_parameters,
92 const DateComponents& date_value)
93 : edit_element_(&element),
94 date_value_(date_value),
95 parameters_(layout_parameters),
96 day_range_(1, 31),
97 hour23_range_(0, 23),
98 minute_range_(0, 59),
99 second_range_(0, 59),
100 millisecond_range_(0, 999) {
101 if (date_value_.GetType() == DateComponents::kDate ||
102 date_value_.GetType() == DateComponents::kDateTimeLocal) {
103 if (parameters_.minimum.GetType() != DateComponents::kInvalid &&
104 parameters_.maximum.GetType() != DateComponents::kInvalid &&
105 parameters_.minimum.FullYear() == parameters_.maximum.FullYear() &&
106 parameters_.minimum.Month() == parameters_.maximum.Month() &&
107 parameters_.minimum.MonthDay() <= parameters_.maximum.MonthDay()) {
108 day_range_.minimum = parameters_.minimum.MonthDay();
109 day_range_.maximum = parameters_.maximum.MonthDay();
110 }
111 }
112
113 if (date_value_.GetType() == DateComponents::kTime ||
114 day_range_.IsSingleton()) {
115 if (parameters_.minimum.GetType() != DateComponents::kInvalid &&
116 parameters_.maximum.GetType() != DateComponents::kInvalid &&
117 parameters_.minimum.Hour() <= parameters_.maximum.Hour()) {
118 hour23_range_.minimum = parameters_.minimum.Hour();
119 hour23_range_.maximum = parameters_.maximum.Hour();
120 }
121 }
122
123 if (hour23_range_.IsSingleton() &&
124 parameters_.minimum.Minute() <= parameters_.maximum.Minute()) {
125 minute_range_.minimum = parameters_.minimum.Minute();
126 minute_range_.maximum = parameters_.maximum.Minute();
127 }
128 if (minute_range_.IsSingleton() &&
129 parameters_.minimum.Second() <= parameters_.maximum.Second()) {
130 second_range_.minimum = parameters_.minimum.Second();
131 second_range_.maximum = parameters_.maximum.Second();
132 }
133 if (second_range_.IsSingleton() &&
134 parameters_.minimum.Millisecond() <= parameters_.maximum.Millisecond()) {
135 millisecond_range_.minimum = parameters_.minimum.Millisecond();
136 millisecond_range_.maximum = parameters_.maximum.Millisecond();
137 }
138 }
139
140 bool DateTimeEditBuilder::Build(const String& format_string) {
141 EditElement().ResetFields();
142 return DateTimeFormat::Parse(format_string, *this);
143 }
144
145 bool DateTimeEditBuilder::NeedMillisecondField() const {
146 return date_value_.Millisecond() ||
147 !GetStepRange()
148 .Minimum()
149 .Remainder(static_cast<int>(kMsPerSecond))
150 .IsZero() ||
151 !GetStepRange()
152 .Step()
153 .Remainder(static_cast<int>(kMsPerSecond))
154 .IsZero();
155 }
156
157 void DateTimeEditBuilder::VisitField(DateTimeFormat::FieldType field_type,
158 int count) {
159 const int kCountForAbbreviatedMonth = 3;
160 const int kCountForFullMonth = 4;
161 const int kCountForNarrowMonth = 5;
162 Document& document = EditElement().GetDocument();
163
164 switch (field_type) {
165 case DateTimeFormat::kFieldTypeDayOfMonth: {
166 DateTimeFieldElement* field = DateTimeDayFieldElement::Create(
167 document, EditElement(), parameters_.placeholder_for_day, day_range_);
168 EditElement().AddField(field);
169 if (ShouldDayOfMonthFieldDisabled()) {
170 field->SetValueAsDate(date_value_);
171 field->SetDisabled();
172 }
173 return;
174 }
175
176 case DateTimeFormat::kFieldTypeHour11: {
177 DateTimeNumericFieldElement::Step step =
178 CreateStep(kMsPerHour, kMsPerHour * 12);
179 DateTimeFieldElement* field = DateTimeHour11FieldElement::Create(
180 document, EditElement(), hour23_range_, step);
181 EditElement().AddField(field);
182 if (ShouldHourFieldDisabled()) {
183 field->SetValueAsDate(date_value_);
184 field->SetDisabled();
185 }
186 return;
187 }
188
189 case DateTimeFormat::kFieldTypeHour12: {
190 DateTimeNumericFieldElement::Step step =
191 CreateStep(kMsPerHour, kMsPerHour * 12);
192 DateTimeFieldElement* field = DateTimeHour12FieldElement::Create(
193 document, EditElement(), hour23_range_, step);
194 EditElement().AddField(field);
195 if (ShouldHourFieldDisabled()) {
196 field->SetValueAsDate(date_value_);
197 field->SetDisabled();
198 }
199 return;
200 }
201
202 case DateTimeFormat::kFieldTypeHour23: {
203 DateTimeNumericFieldElement::Step step =
204 CreateStep(kMsPerHour, kMsPerDay);
205 DateTimeFieldElement* field = DateTimeHour23FieldElement::Create(
206 document, EditElement(), hour23_range_, step);
207 EditElement().AddField(field);
208 if (ShouldHourFieldDisabled()) {
209 field->SetValueAsDate(date_value_);
210 field->SetDisabled();
211 }
212 return;
213 }
214
215 case DateTimeFormat::kFieldTypeHour24: {
216 DateTimeNumericFieldElement::Step step =
217 CreateStep(kMsPerHour, kMsPerDay);
218 DateTimeFieldElement* field = DateTimeHour24FieldElement::Create(
219 document, EditElement(), hour23_range_, step);
220 EditElement().AddField(field);
221 if (ShouldHourFieldDisabled()) {
222 field->SetValueAsDate(date_value_);
223 field->SetDisabled();
224 }
225 return;
226 }
227
228 case DateTimeFormat::kFieldTypeMinute: {
229 DateTimeNumericFieldElement::Step step =
230 CreateStep(kMsPerMinute, kMsPerHour);
231 DateTimeNumericFieldElement* field = DateTimeMinuteFieldElement::Create(
232 document, EditElement(), minute_range_, step);
233 EditElement().AddField(field);
234 if (ShouldMinuteFieldDisabled()) {
235 field->SetValueAsDate(date_value_);
236 field->SetDisabled();
237 }
238 return;
239 }
240
241 case DateTimeFormat::kFieldTypeMonth: // Fallthrough.
242 case DateTimeFormat::kFieldTypeMonthStandAlone: {
243 int min_month = 0, max_month = 11;
244 if (parameters_.minimum.GetType() != DateComponents::kInvalid &&
245 parameters_.maximum.GetType() != DateComponents::kInvalid &&
246 parameters_.minimum.FullYear() == parameters_.maximum.FullYear() &&
247 parameters_.minimum.Month() <= parameters_.maximum.Month()) {
248 min_month = parameters_.minimum.Month();
249 max_month = parameters_.maximum.Month();
250 }
251 DateTimeFieldElement* field;
252 switch (count) {
253 case kCountForNarrowMonth: // Fallthrough.
254 case kCountForAbbreviatedMonth:
255 field = DateTimeSymbolicMonthFieldElement::Create(
256 document, EditElement(),
257 field_type == DateTimeFormat::kFieldTypeMonth
258 ? parameters_.locale.ShortMonthLabels()
259 : parameters_.locale.ShortStandAloneMonthLabels(),
260 min_month, max_month);
261 break;
262 case kCountForFullMonth:
263 field = DateTimeSymbolicMonthFieldElement::Create(
264 document, EditElement(),
265 field_type == DateTimeFormat::kFieldTypeMonth
266 ? parameters_.locale.MonthLabels()
267 : parameters_.locale.StandAloneMonthLabels(),
268 min_month, max_month);
269 break;
270 default:
271 field = DateTimeMonthFieldElement::Create(
272 document, EditElement(), parameters_.placeholder_for_month,
273 DateTimeNumericFieldElement::Range(min_month + 1, max_month + 1));
274 break;
275 }
276 EditElement().AddField(field);
277 if (min_month == max_month && min_month == date_value_.Month() &&
278 date_value_.GetType() != DateComponents::kMonth) {
279 field->SetValueAsDate(date_value_);
280 field->SetDisabled();
281 }
282 return;
283 }
284
285 case DateTimeFormat::kFieldTypePeriod: {
286 DateTimeFieldElement* field = DateTimeAMPMFieldElement::Create(
287 document, EditElement(), parameters_.locale.TimeAMPMLabels());
288 EditElement().AddField(field);
289 if (ShouldAMPMFieldDisabled()) {
290 field->SetValueAsDate(date_value_);
291 field->SetDisabled();
292 }
293 return;
294 }
295
296 case DateTimeFormat::kFieldTypeSecond: {
297 DateTimeNumericFieldElement::Step step =
298 CreateStep(kMsPerSecond, kMsPerMinute);
299 DateTimeNumericFieldElement* field = DateTimeSecondFieldElement::Create(
300 document, EditElement(), second_range_, step);
301 EditElement().AddField(field);
302 if (ShouldSecondFieldDisabled()) {
303 field->SetValueAsDate(date_value_);
304 field->SetDisabled();
305 }
306
307 if (NeedMillisecondField()) {
308 VisitLiteral(parameters_.locale.LocalizedDecimalSeparator());
309 VisitField(DateTimeFormat::kFieldTypeFractionalSecond, 3);
310 }
311 return;
312 }
313
314 case DateTimeFormat::kFieldTypeFractionalSecond: {
315 DateTimeNumericFieldElement::Step step = CreateStep(1, kMsPerSecond);
316 DateTimeNumericFieldElement* field =
317 DateTimeMillisecondFieldElement::Create(document, EditElement(),
318 millisecond_range_, step);
319 EditElement().AddField(field);
320 if (ShouldMillisecondFieldDisabled()) {
321 field->SetValueAsDate(date_value_);
322 field->SetDisabled();
323 }
324 return;
325 }
326
327 case DateTimeFormat::kFieldTypeWeekOfYear: {
328 DateTimeNumericFieldElement::Range range(
329 DateComponents::kMinimumWeekNumber,
330 DateComponents::kMaximumWeekNumber);
331 if (parameters_.minimum.GetType() != DateComponents::kInvalid &&
332 parameters_.maximum.GetType() != DateComponents::kInvalid &&
333 parameters_.minimum.FullYear() == parameters_.maximum.FullYear() &&
334 parameters_.minimum.Week() <= parameters_.maximum.Week()) {
335 range.minimum = parameters_.minimum.Week();
336 range.maximum = parameters_.maximum.Week();
337 }
338 EditElement().AddField(
339 DateTimeWeekFieldElement::Create(document, EditElement(), range));
340 return;
341 }
342
343 case DateTimeFormat::kFieldTypeYear: {
344 DateTimeYearFieldElement::Parameters year_params;
345 if (parameters_.minimum.GetType() == DateComponents::kInvalid) {
346 year_params.minimum_year = DateComponents::MinimumYear();
347 year_params.min_is_specified = false;
348 } else {
349 year_params.minimum_year = parameters_.minimum.FullYear();
350 year_params.min_is_specified = true;
351 }
352 if (parameters_.maximum.GetType() == DateComponents::kInvalid) {
353 year_params.maximum_year = DateComponents::MaximumYear();
354 year_params.max_is_specified = false;
355 } else {
356 year_params.maximum_year = parameters_.maximum.FullYear();
357 year_params.max_is_specified = true;
358 }
359 if (year_params.minimum_year > year_params.maximum_year) {
360 std::swap(year_params.minimum_year, year_params.maximum_year);
361 std::swap(year_params.min_is_specified, year_params.max_is_specified);
362 }
363 year_params.placeholder = parameters_.placeholder_for_year;
364 DateTimeFieldElement* field = DateTimeYearFieldElement::Create(
365 document, EditElement(), year_params);
366 EditElement().AddField(field);
367 if (ShouldYearFieldDisabled()) {
368 field->SetValueAsDate(date_value_);
369 field->SetDisabled();
370 }
371 return;
372 }
373
374 default:
375 return;
376 }
377 }
378
379 bool DateTimeEditBuilder::ShouldAMPMFieldDisabled() const {
380 return ShouldHourFieldDisabled() ||
381 (hour23_range_.minimum < 12 && hour23_range_.maximum < 12 &&
382 date_value_.Hour() < 12) ||
383 (hour23_range_.minimum >= 12 && hour23_range_.maximum >= 12 &&
384 date_value_.Hour() >= 12);
385 }
386
387 bool DateTimeEditBuilder::ShouldDayOfMonthFieldDisabled() const {
388 return day_range_.IsSingleton() &&
389 day_range_.minimum == date_value_.MonthDay() &&
390 date_value_.GetType() != DateComponents::kDate;
391 }
392
393 bool DateTimeEditBuilder::ShouldHourFieldDisabled() const {
394 if (hour23_range_.IsSingleton() &&
395 hour23_range_.minimum == date_value_.Hour() &&
396 !(ShouldMinuteFieldDisabled() && ShouldSecondFieldDisabled() &&
397 ShouldMillisecondFieldDisabled()))
398 return true;
399
400 if (date_value_.GetType() == DateComponents::kTime)
401 return false;
402 DCHECK_EQ(date_value_.GetType(), DateComponents::kDateTimeLocal);
403
404 if (ShouldDayOfMonthFieldDisabled()) {
405 DCHECK_EQ(parameters_.minimum.FullYear(), parameters_.maximum.FullYear());
406 DCHECK_EQ(parameters_.minimum.Month(), parameters_.maximum.Month());
407 return false;
408 }
409
410 const Decimal decimal_ms_per_day(static_cast<int>(kMsPerDay));
411 Decimal hour_part_of_minimum =
412 (GetStepRange().StepBase().Abs().Remainder(decimal_ms_per_day) /
413 static_cast<int>(kMsPerHour))
414 .Floor();
415 return hour_part_of_minimum == date_value_.Hour() &&
416 GetStepRange().Step().Remainder(decimal_ms_per_day).IsZero();
417 }
418
419 bool DateTimeEditBuilder::ShouldMillisecondFieldDisabled() const {
420 if (millisecond_range_.IsSingleton() &&
421 millisecond_range_.minimum == date_value_.Millisecond())
422 return true;
423
424 const Decimal decimal_ms_per_second(static_cast<int>(kMsPerSecond));
425 return GetStepRange().StepBase().Abs().Remainder(decimal_ms_per_second) ==
426 date_value_.Millisecond() &&
427 GetStepRange().Step().Remainder(decimal_ms_per_second).IsZero();
428 }
429
430 bool DateTimeEditBuilder::ShouldMinuteFieldDisabled() const {
431 if (minute_range_.IsSingleton() &&
432 minute_range_.minimum == date_value_.Minute())
433 return true;
434
435 const Decimal decimal_ms_per_hour(static_cast<int>(kMsPerHour));
436 Decimal minute_part_of_minimum =
437 (GetStepRange().StepBase().Abs().Remainder(decimal_ms_per_hour) /
438 static_cast<int>(kMsPerMinute))
439 .Floor();
440 return minute_part_of_minimum == date_value_.Minute() &&
441 GetStepRange().Step().Remainder(decimal_ms_per_hour).IsZero();
442 }
443
444 bool DateTimeEditBuilder::ShouldSecondFieldDisabled() const {
445 if (second_range_.IsSingleton() &&
446 second_range_.minimum == date_value_.Second())
447 return true;
448
449 const Decimal decimal_ms_per_minute(static_cast<int>(kMsPerMinute));
450 Decimal second_part_of_minimum =
451 (GetStepRange().StepBase().Abs().Remainder(decimal_ms_per_minute) /
452 static_cast<int>(kMsPerSecond))
453 .Floor();
454 return second_part_of_minimum == date_value_.Second() &&
455 GetStepRange().Step().Remainder(decimal_ms_per_minute).IsZero();
456 }
457
458 bool DateTimeEditBuilder::ShouldYearFieldDisabled() const {
459 return parameters_.minimum.GetType() != DateComponents::kInvalid &&
460 parameters_.maximum.GetType() != DateComponents::kInvalid &&
461 parameters_.minimum.FullYear() == parameters_.maximum.FullYear() &&
462 parameters_.minimum.FullYear() == date_value_.FullYear();
463 }
464
465 void DateTimeEditBuilder::VisitLiteral(const String& text) {
466 DEFINE_STATIC_LOCAL(AtomicString, text_pseudo_id,
467 ("-webkit-datetime-edit-text"));
468 DCHECK_GT(text.length(), 0u);
469 HTMLDivElement* element = HTMLDivElement::Create(EditElement().GetDocument());
470 element->SetShadowPseudoId(text_pseudo_id);
471 if (parameters_.locale.IsRTL() && text.length()) {
472 CharDirection dir = Direction(text[0]);
473 if (dir == kSegmentSeparator || dir == kWhiteSpaceNeutral ||
474 dir == kOtherNeutral)
475 element->AppendChild(Text::Create(EditElement().GetDocument(),
476 String(&kRightToLeftMarkCharacter, 1)));
477 }
478 element->AppendChild(Text::Create(EditElement().GetDocument(), text));
479 EditElement().FieldsWrapperElement()->AppendChild(element);
480 }
481
482 DateTimeEditElement& DateTimeEditBuilder::EditElement() const {
483 return *edit_element_;
484 }
485
486 DateTimeNumericFieldElement::Step DateTimeEditBuilder::CreateStep(
487 double ms_per_field_unit,
488 double ms_per_field_size) const {
489 const Decimal ms_per_field_unit_decimal(static_cast<int>(ms_per_field_unit));
490 const Decimal ms_per_field_size_decimal(static_cast<int>(ms_per_field_size));
491 Decimal step_milliseconds = GetStepRange().Step();
492 DCHECK(!ms_per_field_unit_decimal.IsZero());
493 DCHECK(!ms_per_field_size_decimal.IsZero());
494 DCHECK(!step_milliseconds.IsZero());
495
496 DateTimeNumericFieldElement::Step step(1, 0);
497
498 if (step_milliseconds.Remainder(ms_per_field_size_decimal).IsZero())
499 step_milliseconds = ms_per_field_size_decimal;
500
501 if (ms_per_field_size_decimal.Remainder(step_milliseconds).IsZero() &&
502 step_milliseconds.Remainder(ms_per_field_unit_decimal).IsZero()) {
503 step.step = static_cast<int>(
504 (step_milliseconds / ms_per_field_unit_decimal).ToDouble());
505 step.step_base = static_cast<int>(
506 (GetStepRange().StepBase() / ms_per_field_unit_decimal)
507 .Floor()
508 .Remainder(ms_per_field_size_decimal / ms_per_field_unit_decimal)
509 .ToDouble());
510 }
511 return step;
512 }
513
514 // ----------------------------
515
516 DateTimeEditElement::EditControlOwner::~EditControlOwner() {}
517
518 DateTimeEditElement::DateTimeEditElement(Document& document,
519 EditControlOwner& edit_control_owner)
520 : HTMLDivElement(document), edit_control_owner_(&edit_control_owner) {
521 SetHasCustomStyleCallbacks();
522 }
523
524 DateTimeEditElement::~DateTimeEditElement() {}
525
526 DEFINE_TRACE(DateTimeEditElement) {
527 visitor->Trace(fields_);
528 visitor->Trace(edit_control_owner_);
529 HTMLDivElement::Trace(visitor);
530 }
531
532 inline Element* DateTimeEditElement::FieldsWrapperElement() const {
533 DCHECK(FirstChild());
534 return ToElementOrDie(FirstChild());
535 }
536
537 void DateTimeEditElement::AddField(DateTimeFieldElement* field) {
538 if (fields_.size() >= kMaximumNumberOfFields)
539 return;
540 fields_.push_back(field);
541 FieldsWrapperElement()->AppendChild(field);
542 }
543
544 bool DateTimeEditElement::AnyEditableFieldsHaveValues() const {
545 for (const auto& field : fields_) {
546 if (!field->IsDisabled() && field->HasValue())
547 return true;
548 }
549 return false;
550 }
551
552 void DateTimeEditElement::BlurByOwner() {
553 if (DateTimeFieldElement* field = FocusedField())
554 field->blur();
555 }
556
557 DateTimeEditElement* DateTimeEditElement::Create(
558 Document& document,
559 EditControlOwner& edit_control_owner) {
560 DateTimeEditElement* container =
561 new DateTimeEditElement(document, edit_control_owner);
562 container->SetShadowPseudoId(AtomicString("-webkit-datetime-edit"));
563 container->setAttribute(idAttr, ShadowElementNames::DateTimeEdit());
564 return container;
565 }
566
567 PassRefPtr<ComputedStyle> DateTimeEditElement::CustomStyleForLayoutObject() {
568 // FIXME: This is a kind of layout. We might want to introduce new
569 // layoutObject.
570 RefPtr<ComputedStyle> original_style = OriginalStyleForLayoutObject();
571 RefPtr<ComputedStyle> style = ComputedStyle::Clone(*original_style);
572 float width = 0;
573 for (Node* child = FieldsWrapperElement()->FirstChild(); child;
574 child = child->nextSibling()) {
575 if (!child->IsElementNode())
576 continue;
577 Element* child_element = ToElement(child);
578 if (child_element->IsDateTimeFieldElement()) {
579 // We need to pass the ComputedStyle of this element because child
580 // elements can't resolve inherited style at this timing.
581 width += static_cast<DateTimeFieldElement*>(child_element)
582 ->MaximumWidth(*style);
583 } else {
584 // ::-webkit-datetime-edit-text case. It has no
585 // border/padding/margin in html.css.
586 width += DateTimeFieldElement::ComputeTextWidth(
587 *style, child_element->textContent());
588 }
589 }
590 style->SetWidth(Length(ceilf(width), kFixed));
591 style->SetUnique();
592 return style.Release();
593 }
594
595 void DateTimeEditElement::DidBlurFromField(WebFocusType focus_type) {
596 if (edit_control_owner_)
597 edit_control_owner_->DidBlurFromControl(focus_type);
598 }
599
600 void DateTimeEditElement::DidFocusOnField(WebFocusType focus_type) {
601 if (edit_control_owner_)
602 edit_control_owner_->DidFocusOnControl(focus_type);
603 }
604
605 void DateTimeEditElement::DisabledStateChanged() {
606 UpdateUIState();
607 }
608
609 DateTimeFieldElement* DateTimeEditElement::FieldAt(size_t field_index) const {
610 return field_index < fields_.size() ? fields_[field_index].Get() : 0;
611 }
612
613 size_t DateTimeEditElement::FieldIndexOf(
614 const DateTimeFieldElement& field) const {
615 for (size_t field_index = 0; field_index < fields_.size(); ++field_index) {
616 if (fields_[field_index] == &field)
617 return field_index;
618 }
619 return kInvalidFieldIndex;
620 }
621
622 void DateTimeEditElement::FocusIfNoFocus() {
623 if (FocusedFieldIndex() != kInvalidFieldIndex)
624 return;
625 FocusOnNextFocusableField(0);
626 }
627
628 void DateTimeEditElement::FocusByOwner(Element* old_focused_element) {
629 if (old_focused_element && old_focused_element->IsDateTimeFieldElement()) {
630 DateTimeFieldElement* old_focused_field =
631 static_cast<DateTimeFieldElement*>(old_focused_element);
632 size_t index = FieldIndexOf(*old_focused_field);
633 GetDocument().UpdateStyleAndLayoutTreeForNode(old_focused_field);
634 if (index != kInvalidFieldIndex && old_focused_field->IsFocusable()) {
635 old_focused_field->focus();
636 return;
637 }
638 }
639 FocusOnNextFocusableField(0);
640 }
641
642 DateTimeFieldElement* DateTimeEditElement::FocusedField() const {
643 return FieldAt(FocusedFieldIndex());
644 }
645
646 size_t DateTimeEditElement::FocusedFieldIndex() const {
647 Element* const focused_field_element = GetDocument().FocusedElement();
648 for (size_t field_index = 0; field_index < fields_.size(); ++field_index) {
649 if (fields_[field_index] == focused_field_element)
650 return field_index;
651 }
652 return kInvalidFieldIndex;
653 }
654
655 void DateTimeEditElement::FieldValueChanged() {
656 if (edit_control_owner_)
657 edit_control_owner_->EditControlValueChanged();
658 }
659
660 bool DateTimeEditElement::FocusOnNextFocusableField(size_t start_index) {
661 GetDocument().UpdateStyleAndLayoutTreeIgnorePendingStylesheets();
662 for (size_t field_index = start_index; field_index < fields_.size();
663 ++field_index) {
664 if (fields_[field_index]->IsFocusable()) {
665 fields_[field_index]->focus();
666 return true;
667 }
668 }
669 return false;
670 }
671
672 bool DateTimeEditElement::FocusOnNextField(const DateTimeFieldElement& field) {
673 const size_t start_field_index = FieldIndexOf(field);
674 if (start_field_index == kInvalidFieldIndex)
675 return false;
676 return FocusOnNextFocusableField(start_field_index + 1);
677 }
678
679 bool DateTimeEditElement::FocusOnPreviousField(
680 const DateTimeFieldElement& field) {
681 const size_t start_field_index = FieldIndexOf(field);
682 if (start_field_index == kInvalidFieldIndex)
683 return false;
684 GetDocument().UpdateStyleAndLayoutTreeIgnorePendingStylesheets();
685 size_t field_index = start_field_index;
686 while (field_index > 0) {
687 --field_index;
688 if (fields_[field_index]->IsFocusable()) {
689 fields_[field_index]->focus();
690 return true;
691 }
692 }
693 return false;
694 }
695
696 bool DateTimeEditElement::IsDateTimeEditElement() const {
697 return true;
698 }
699
700 bool DateTimeEditElement::IsDisabled() const {
701 return edit_control_owner_ &&
702 edit_control_owner_->IsEditControlOwnerDisabled();
703 }
704
705 bool DateTimeEditElement::IsFieldOwnerDisabled() const {
706 return IsDisabled();
707 }
708
709 bool DateTimeEditElement::IsFieldOwnerReadOnly() const {
710 return IsReadOnly();
711 }
712
713 bool DateTimeEditElement::IsReadOnly() const {
714 return edit_control_owner_ &&
715 edit_control_owner_->IsEditControlOwnerReadOnly();
716 }
717
718 void DateTimeEditElement::GetLayout(const LayoutParameters& layout_parameters,
719 const DateComponents& date_value) {
720 // TODO(tkent): We assume this function never dispatches events. However this
721 // can dispatch 'blur' event in Node::removeChild().
722
723 DEFINE_STATIC_LOCAL(AtomicString, fields_wrapper_pseudo_id,
724 ("-webkit-datetime-edit-fields-wrapper"));
725 if (!HasChildren()) {
726 HTMLDivElement* element = HTMLDivElement::Create(GetDocument());
727 element->SetShadowPseudoId(fields_wrapper_pseudo_id);
728 AppendChild(element);
729 }
730 Element* fields_wrapper = FieldsWrapperElement();
731
732 size_t focused_field_index = this->FocusedFieldIndex();
733 DateTimeFieldElement* const focused_field = FieldAt(focused_field_index);
734 const AtomicString focused_field_id =
735 focused_field ? focused_field->ShadowPseudoId() : g_null_atom;
736
737 DateTimeEditBuilder builder(*this, layout_parameters, date_value);
738 Node* last_child_to_be_removed = fields_wrapper->LastChild();
739 if (!builder.Build(layout_parameters.date_time_format) || fields_.IsEmpty()) {
740 last_child_to_be_removed = fields_wrapper->LastChild();
741 builder.Build(layout_parameters.fallback_date_time_format);
742 }
743
744 if (focused_field_index != kInvalidFieldIndex) {
745 for (size_t field_index = 0; field_index < fields_.size(); ++field_index) {
746 if (fields_[field_index]->ShadowPseudoId() == focused_field_id) {
747 focused_field_index = field_index;
748 break;
749 }
750 }
751 if (DateTimeFieldElement* field =
752 FieldAt(std::min(focused_field_index, fields_.size() - 1)))
753 field->focus();
754 }
755
756 if (last_child_to_be_removed) {
757 for (Node* child_node = fields_wrapper->FirstChild(); child_node;
758 child_node = fields_wrapper->FirstChild()) {
759 fields_wrapper->RemoveChild(child_node);
760 if (child_node == last_child_to_be_removed)
761 break;
762 }
763 SetNeedsStyleRecalc(
764 kSubtreeStyleChange,
765 StyleChangeReasonForTracing::Create(StyleChangeReason::kControl));
766 }
767 }
768
769 AtomicString DateTimeEditElement::LocaleIdentifier() const {
770 return edit_control_owner_ ? edit_control_owner_->LocaleIdentifier()
771 : g_null_atom;
772 }
773
774 void DateTimeEditElement::FieldDidChangeValueByKeyboard() {
775 if (edit_control_owner_)
776 edit_control_owner_->EditControlDidChangeValueByKeyboard();
777 }
778
779 void DateTimeEditElement::ReadOnlyStateChanged() {
780 UpdateUIState();
781 }
782
783 void DateTimeEditElement::ResetFields() {
784 for (const auto& field : fields_)
785 field->RemoveEventHandler();
786 fields_.Shrink(0);
787 }
788
789 void DateTimeEditElement::DefaultEventHandler(Event* event) {
790 // In case of control owner forward event to control, e.g. DOM
791 // dispatchEvent method.
792 if (DateTimeFieldElement* field = FocusedField()) {
793 field->DefaultEventHandler(event);
794 if (event->DefaultHandled())
795 return;
796 }
797
798 HTMLDivElement::DefaultEventHandler(event);
799 }
800
801 void DateTimeEditElement::SetValueAsDate(
802 const LayoutParameters& layout_parameters,
803 const DateComponents& date) {
804 GetLayout(layout_parameters, date);
805 for (const auto& field : fields_)
806 field->SetValueAsDate(date);
807 }
808
809 void DateTimeEditElement::SetValueAsDateTimeFieldsState(
810 const DateTimeFieldsState& date_time_fields_state) {
811 for (const auto& field : fields_)
812 field->SetValueAsDateTimeFieldsState(date_time_fields_state);
813 }
814
815 void DateTimeEditElement::SetEmptyValue(
816 const LayoutParameters& layout_parameters,
817 const DateComponents& date_for_read_only_field) {
818 GetLayout(layout_parameters, date_for_read_only_field);
819 for (const auto& field : fields_)
820 field->SetEmptyValue(DateTimeFieldElement::kDispatchNoEvent);
821 }
822
823 bool DateTimeEditElement::HasFocusedField() {
824 return FocusedFieldIndex() != kInvalidFieldIndex;
825 }
826
827 void DateTimeEditElement::SetOnlyYearMonthDay(const DateComponents& date) {
828 DCHECK_EQ(date.GetType(), DateComponents::kDate);
829
830 if (!edit_control_owner_)
831 return;
832
833 DateTimeFieldsState date_time_fields_state = ValueAsDateTimeFieldsState();
834 date_time_fields_state.SetYear(date.FullYear());
835 date_time_fields_state.SetMonth(date.Month() + 1);
836 date_time_fields_state.SetDayOfMonth(date.MonthDay());
837 SetValueAsDateTimeFieldsState(date_time_fields_state);
838 edit_control_owner_->EditControlValueChanged();
839 }
840
841 void DateTimeEditElement::StepDown() {
842 if (DateTimeFieldElement* const field = FocusedField())
843 field->StepDown();
844 }
845
846 void DateTimeEditElement::StepUp() {
847 if (DateTimeFieldElement* const field = FocusedField())
848 field->StepUp();
849 }
850
851 void DateTimeEditElement::UpdateUIState() {
852 if (IsDisabled()) {
853 if (DateTimeFieldElement* field = FocusedField())
854 field->blur();
855 }
856 }
857
858 String DateTimeEditElement::Value() const {
859 if (!edit_control_owner_)
860 return g_empty_string;
861 return edit_control_owner_->FormatDateTimeFieldsState(
862 ValueAsDateTimeFieldsState());
863 }
864
865 DateTimeFieldsState DateTimeEditElement::ValueAsDateTimeFieldsState() const {
866 DateTimeFieldsState date_time_fields_state;
867 for (const auto& field : fields_)
868 field->PopulateDateTimeFieldsState(date_time_fields_state);
869 return date_time_fields_state;
870 }
871
872 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698