1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
33 #include "core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h"
34
35 #include "CSSValueKeywords.h"
36 #include "RuntimeEnabledFeatures.h"
37 #include "core/dom/shadow/ShadowRoot.h"
38 #include "core/events/KeyboardEvent.h"
39 #include "core/html/HTMLDataListElement.h"
40 #include "core/html/HTMLInputElement.h"
41 #include "core/html/HTMLOptionElement.h"
42 #include "core/html/forms/DateTimeFieldsState.h"
43 #include "core/html/forms/FormController.h"
44 #include "core/html/shadow/ShadowElementNames.h"
45 #include "core/page/FocusController.h"
46 #include "core/page/Page.h"
47 #include "core/rendering/RenderTheme.h"
48 #include "platform/DateComponents.h"
49 #include "platform/text/DateTimeFormat.h"
50 #include "platform/text/PlatformLocale.h"
51 #include "wtf/DateMath.h"
52
53 namespace WebCore {
54
55 class DateTimeFormatValidator : public DateTimeFormat::TokenHandler {
56 public:
DateTimeFormatValidator()57 DateTimeFormatValidator()
58 : m_hasYear(false)
59 , m_hasMonth(false)
60 , m_hasWeek(false)
61 , m_hasDay(false)
62 , m_hasAMPM(false)
63 , m_hasHour(false)
64 , m_hasMinute(false)
65 , m_hasSecond(false) { }
66
67 virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL;
visitLiteral(const String &)68 virtual void visitLiteral(const String&) OVERRIDE FINAL { }
69
70 bool validateFormat(const String& format, const BaseMultipleFieldsDateAndTimeInputType&);
71
72 private:
73 bool m_hasYear;
74 bool m_hasMonth;
75 bool m_hasWeek;
76 bool m_hasDay;
77 bool m_hasAMPM;
78 bool m_hasHour;
79 bool m_hasMinute;
80 bool m_hasSecond;
81 };
82
visitField(DateTimeFormat::FieldType fieldType,int)83 void DateTimeFormatValidator::visitField(DateTimeFormat::FieldType fieldType, int)
84 {
85 switch (fieldType) {
86 case DateTimeFormat::FieldTypeYear:
87 m_hasYear = true;
88 break;
89 case DateTimeFormat::FieldTypeMonth: // Fallthrough.
90 case DateTimeFormat::FieldTypeMonthStandAlone:
91 m_hasMonth = true;
92 break;
93 case DateTimeFormat::FieldTypeWeekOfYear:
94 m_hasWeek = true;
95 break;
96 case DateTimeFormat::FieldTypeDayOfMonth:
97 m_hasDay = true;
98 break;
99 case DateTimeFormat::FieldTypePeriod:
100 m_hasAMPM = true;
101 break;
102 case DateTimeFormat::FieldTypeHour11: // Fallthrough.
103 case DateTimeFormat::FieldTypeHour12:
104 m_hasHour = true;
105 break;
106 case DateTimeFormat::FieldTypeHour23: // Fallthrough.
107 case DateTimeFormat::FieldTypeHour24:
108 m_hasHour = true;
109 m_hasAMPM = true;
110 break;
111 case DateTimeFormat::FieldTypeMinute:
112 m_hasMinute = true;
113 break;
114 case DateTimeFormat::FieldTypeSecond:
115 m_hasSecond = true;
116 break;
117 default:
118 break;
119 }
120 }
121
validateFormat(const String & format,const BaseMultipleFieldsDateAndTimeInputType & inputType)122 bool DateTimeFormatValidator::validateFormat(const String& format, const BaseMultipleFieldsDateAndTimeInputType& inputType)
123 {
124 if (!DateTimeFormat::parse(format, *this))
125 return false;
126 return inputType.isValidFormat(m_hasYear, m_hasMonth, m_hasWeek, m_hasDay, m_hasAMPM, m_hasHour, m_hasMinute, m_hasSecond);
127 }
128
dateTimeEditElement() const129 DateTimeEditElement* BaseMultipleFieldsDateAndTimeInputType::dateTimeEditElement() const
130 {
131 return toDateTimeEditElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::dateTimeEdit()));
132 }
133
spinButtonElement() const134 SpinButtonElement* BaseMultipleFieldsDateAndTimeInputType::spinButtonElement() const
135 {
136 return toSpinButtonElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::spinButton()));
137 }
138
clearButtonElement() const139 ClearButtonElement* BaseMultipleFieldsDateAndTimeInputType::clearButtonElement() const
140 {
141 return toClearButtonElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::clearButton()));
142 }
143
pickerIndicatorElement() const144 PickerIndicatorElement* BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorElement() const
145 {
146 return toPickerIndicatorElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::pickerIndicator()));
147 }
148
containsFocusedShadowElement() const149 inline bool BaseMultipleFieldsDateAndTimeInputType::containsFocusedShadowElement() const
150 {
151 return element().userAgentShadowRoot()->contains(element().document().focusedElement());
152 }
153
didBlurFromControl()154 void BaseMultipleFieldsDateAndTimeInputType::didBlurFromControl()
155 {
156 // We don't need to call blur(). This function is called when control
157 // lost focus.
158
159 if (containsFocusedShadowElement())
160 return;
161 RefPtr<HTMLInputElement> protector(element());
162 // Remove focus ring by CSS "focus" pseudo class.
163 element().setFocus(false);
164 }
165
didFocusOnControl()166 void BaseMultipleFieldsDateAndTimeInputType::didFocusOnControl()
167 {
168 // We don't need to call focus(). This function is called when control
169 // got focus.
170
171 if (!containsFocusedShadowElement())
172 return;
173 // Add focus ring by CSS "focus" pseudo class.
174 // FIXME: Setting the focus flag to non-focused element is too tricky.
175 element().setFocus(true);
176 }
177
editControlValueChanged()178 void BaseMultipleFieldsDateAndTimeInputType::editControlValueChanged()
179 {
180 RefPtr<HTMLInputElement> input(element());
181 String oldValue = input->value();
182 String newValue = sanitizeValue(dateTimeEditElement()->value());
183 // Even if oldValue is null and newValue is "", we should assume they are same.
184 if ((oldValue.isEmpty() && newValue.isEmpty()) || oldValue == newValue) {
185 input->setNeedsValidityCheck();
186 } else {
187 input->setValueInternal(newValue, DispatchNoEvent);
188 input->setNeedsStyleRecalc();
189 input->dispatchFormControlInputEvent();
190 input->dispatchFormControlChangeEvent();
191 }
192 input->notifyFormStateChanged();
193 input->updateClearButtonVisibility();
194 }
195
hasCustomFocusLogic() const196 bool BaseMultipleFieldsDateAndTimeInputType::hasCustomFocusLogic() const
197 {
198 return false;
199 }
200
isEditControlOwnerDisabled() const201 bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerDisabled() const
202 {
203 return element().isDisabledFormControl();
204 }
205
isEditControlOwnerReadOnly() const206 bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerReadOnly() const
207 {
208 return element().isReadOnly();
209 }
210
focusAndSelectSpinButtonOwner()211 void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectSpinButtonOwner()
212 {
213 if (DateTimeEditElement* edit = dateTimeEditElement())
214 edit->focusIfNoFocus();
215 }
216
shouldSpinButtonRespondToMouseEvents()217 bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToMouseEvents()
218 {
219 return !element().isDisabledOrReadOnly();
220 }
221
shouldSpinButtonRespondToWheelEvents()222 bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToWheelEvents()
223 {
224 if (!shouldSpinButtonRespondToMouseEvents())
225 return false;
226 if (DateTimeEditElement* edit = dateTimeEditElement())
227 return edit->hasFocusedField();
228 return false;
229 }
230
spinButtonStepDown()231 void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepDown()
232 {
233 if (DateTimeEditElement* edit = dateTimeEditElement())
234 edit->stepDown();
235 }
236
spinButtonStepUp()237 void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepUp()
238 {
239 if (DateTimeEditElement* edit = dateTimeEditElement())
240 edit->stepUp();
241 }
242
isPickerIndicatorOwnerDisabledOrReadOnly() const243 bool BaseMultipleFieldsDateAndTimeInputType::isPickerIndicatorOwnerDisabledOrReadOnly() const
244 {
245 return element().isDisabledOrReadOnly();
246 }
247
pickerIndicatorChooseValue(const String & value)248 void BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorChooseValue(const String& value)
249 {
250 if (element().isValidValue(value)) {
251 element().setValue(value, DispatchInputAndChangeEvent);
252 return;
253 }
254
255 DateTimeEditElement* edit = this->dateTimeEditElement();
256 if (!edit)
257 return;
258 DateComponents date;
259 unsigned end;
260 if (date.parseDate(value, 0, end) && end == value.length())
261 edit->setOnlyYearMonthDay(date);
262 }
263
pickerIndicatorChooseValue(double value)264 void BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorChooseValue(double value)
265 {
266 ASSERT(std::isfinite(value) || std::isnan(value));
267 if (std::isnan(value))
268 element().setValue(emptyString(), DispatchInputAndChangeEvent);
269 else
270 element().setValueAsNumber(value, ASSERT_NO_EXCEPTION, DispatchInputAndChangeEvent);
271 }
272
setupDateTimeChooserParameters(DateTimeChooserParameters & parameters)273 bool BaseMultipleFieldsDateAndTimeInputType::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
274 {
275 return element().setupDateTimeChooserParameters(parameters);
276 }
277
BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement & element)278 BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement& element)
279 : BaseDateAndTimeInputType(element)
280 , m_isDestroyingShadowSubtree(false)
281 , m_pickerIndicatorIsVisible(false)
282 , m_pickerIndicatorIsAlwaysVisible(false)
283 {
284 }
285
~BaseMultipleFieldsDateAndTimeInputType()286 BaseMultipleFieldsDateAndTimeInputType::~BaseMultipleFieldsDateAndTimeInputType()
287 {
288 if (SpinButtonElement* element = spinButtonElement())
289 element->removeSpinButtonOwner();
290 if (ClearButtonElement* element = clearButtonElement())
291 element->removeClearButtonOwner();
292 if (DateTimeEditElement* element = dateTimeEditElement())
293 element->removeEditControlOwner();
294 if (PickerIndicatorElement* element = pickerIndicatorElement())
295 element->removePickerIndicatorOwner();
296 }
297
badInputText() const298 String BaseMultipleFieldsDateAndTimeInputType::badInputText() const
299 {
300 return locale().queryString(blink::WebLocalizedString::ValidationBadInputForDateTime);
301 }
302
blur()303 void BaseMultipleFieldsDateAndTimeInputType::blur()
304 {
305 if (DateTimeEditElement* edit = dateTimeEditElement())
306 edit->blurByOwner();
307 }
308
customStyleForRenderer(PassRefPtr<RenderStyle> originalStyle)309 PassRefPtr<RenderStyle> BaseMultipleFieldsDateAndTimeInputType::customStyleForRenderer(PassRefPtr<RenderStyle> originalStyle)
310 {
311 EDisplay originalDisplay = originalStyle->display();
312 EDisplay newDisplay = originalDisplay;
313 if (originalDisplay == INLINE || originalDisplay == INLINE_BLOCK)
314 newDisplay = INLINE_FLEX;
315 else if (originalDisplay == BLOCK)
316 newDisplay = FLEX;
317 TextDirection contentDirection = element().locale().isRTL() ? RTL : LTR;
318 if (originalStyle->direction() == contentDirection && originalDisplay == newDisplay)
319 return originalStyle;
320
321 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
322 style->setDirection(contentDirection);
323 style->setDisplay(newDisplay);
324 style->setUnique();
325 return style.release();
326 }
327
createShadowSubtree()328 void BaseMultipleFieldsDateAndTimeInputType::createShadowSubtree()
329 {
330 ASSERT(element().shadow());
331
332 // Element must not have a renderer here, because if it did
333 // DateTimeEditElement::customStyleForRenderer() is called in appendChild()
334 // before the field wrapper element is created.
335 // FIXME: This code should not depend on such craziness.
336 ASSERT(!element().renderer());
337
338 Document& document = element().document();
339 ContainerNode* container = element().userAgentShadowRoot();
340
341 container->appendChild(DateTimeEditElement::create(document, *this));
342 updateView();
343 container->appendChild(ClearButtonElement::create(document, *this));
344 container->appendChild(SpinButtonElement::create(document, *this));
345
346 bool shouldAddPickerIndicator = false;
347 if (InputType::themeSupportsDataListUI(this))
348 shouldAddPickerIndicator = true;
349 if (RenderTheme::theme().supportsCalendarPicker(formControlType())) {
350 shouldAddPickerIndicator = true;
351 m_pickerIndicatorIsAlwaysVisible = true;
352 }
353 if (shouldAddPickerIndicator) {
354 container->appendChild(PickerIndicatorElement::create(document, *this));
355 m_pickerIndicatorIsVisible = true;
356 updatePickerIndicatorVisibility();
357 }
358 }
359
destroyShadowSubtree()360 void BaseMultipleFieldsDateAndTimeInputType::destroyShadowSubtree()
361 {
362 ASSERT(!m_isDestroyingShadowSubtree);
363 m_isDestroyingShadowSubtree = true;
364 if (SpinButtonElement* element = spinButtonElement())
365 element->removeSpinButtonOwner();
366 if (ClearButtonElement* element = clearButtonElement())
367 element->removeClearButtonOwner();
368 if (DateTimeEditElement* element = dateTimeEditElement())
369 element->removeEditControlOwner();
370 if (PickerIndicatorElement* element = pickerIndicatorElement())
371 element->removePickerIndicatorOwner();
372
373 // If a field element has focus, set focus back to the <input> itself before
374 // deleting the field. This prevents unnecessary focusout/blur events.
375 if (containsFocusedShadowElement())
376 element().focus();
377
378 BaseDateAndTimeInputType::destroyShadowSubtree();
379 m_isDestroyingShadowSubtree = false;
380 }
381
handleFocusEvent(Element * oldFocusedElement,FocusDirection direction)382 void BaseMultipleFieldsDateAndTimeInputType::handleFocusEvent(Element* oldFocusedElement, FocusDirection direction)
383 {
384 DateTimeEditElement* edit = dateTimeEditElement();
385 if (!edit || m_isDestroyingShadowSubtree)
386 return;
387 if (direction == FocusDirectionBackward) {
388 if (element().document().page())
389 element().document().page()->focusController().advanceFocus(direction);
390 } else if (direction == FocusDirectionNone || direction == FocusDirectionMouse || direction == FocusDirectionPage) {
391 edit->focusByOwner(oldFocusedElement);
392 } else {
393 edit->focusByOwner();
394 }
395 }
396
forwardEvent(Event * event)397 void BaseMultipleFieldsDateAndTimeInputType::forwardEvent(Event* event)
398 {
399 if (SpinButtonElement* element = spinButtonElement()) {
400 element->forwardEvent(event);
401 if (event->defaultHandled())
402 return;
403 }
404
405 if (DateTimeEditElement* edit = dateTimeEditElement())
406 edit->defaultEventHandler(event);
407 }
408
disabledAttributeChanged()409 void BaseMultipleFieldsDateAndTimeInputType::disabledAttributeChanged()
410 {
411 spinButtonElement()->releaseCapture();
412 clearButtonElement()->releaseCapture();
413 if (DateTimeEditElement* edit = dateTimeEditElement())
414 edit->disabledStateChanged();
415 }
416
requiredAttributeChanged()417 void BaseMultipleFieldsDateAndTimeInputType::requiredAttributeChanged()
418 {
419 clearButtonElement()->releaseCapture();
420 updateClearButtonVisibility();
421 }
422
handleKeydownEvent(KeyboardEvent * event)423 void BaseMultipleFieldsDateAndTimeInputType::handleKeydownEvent(KeyboardEvent* event)
424 {
425 if (m_pickerIndicatorIsVisible
426 && ((event->keyIdentifier() == "Down" && event->getModifierState("Alt")) || (RenderTheme::theme().shouldOpenPickerWithF4Key() && event->keyIdentifier() == "F4"))) {
427 if (PickerIndicatorElement* element = pickerIndicatorElement())
428 element->openPopup();
429 event->setDefaultHandled();
430 } else {
431 forwardEvent(event);
432 }
433 }
434
hasBadInput() const435 bool BaseMultipleFieldsDateAndTimeInputType::hasBadInput() const
436 {
437 DateTimeEditElement* edit = dateTimeEditElement();
438 return element().value().isEmpty() && edit && edit->anyEditableFieldsHaveValues();
439 }
440
localeIdentifier() const441 AtomicString BaseMultipleFieldsDateAndTimeInputType::localeIdentifier() const
442 {
443 return element().computeInheritedLanguage();
444 }
445
minOrMaxAttributeChanged()446 void BaseMultipleFieldsDateAndTimeInputType::minOrMaxAttributeChanged()
447 {
448 updateView();
449 }
450
readonlyAttributeChanged()451 void BaseMultipleFieldsDateAndTimeInputType::readonlyAttributeChanged()
452 {
453 spinButtonElement()->releaseCapture();
454 clearButtonElement()->releaseCapture();
455 if (DateTimeEditElement* edit = dateTimeEditElement())
456 edit->readOnlyStateChanged();
457 }
458
restoreFormControlState(const FormControlState & state)459 void BaseMultipleFieldsDateAndTimeInputType::restoreFormControlState(const FormControlState& state)
460 {
461 DateTimeEditElement* edit = dateTimeEditElement();
462 if (!edit)
463 return;
464 DateTimeFieldsState dateTimeFieldsState = DateTimeFieldsState::restoreFormControlState(state);
465 edit->setValueAsDateTimeFieldsState(dateTimeFieldsState);
466 element().setValueInternal(sanitizeValue(edit->value()), DispatchNoEvent);
467 updateClearButtonVisibility();
468 }
469
saveFormControlState() const470 FormControlState BaseMultipleFieldsDateAndTimeInputType::saveFormControlState() const
471 {
472 if (DateTimeEditElement* edit = dateTimeEditElement())
473 return edit->valueAsDateTimeFieldsState().saveFormControlState();
474 return FormControlState();
475 }
476
setValue(const String & sanitizedValue,bool valueChanged,TextFieldEventBehavior eventBehavior)477 void BaseMultipleFieldsDateAndTimeInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
478 {
479 InputType::setValue(sanitizedValue, valueChanged, eventBehavior);
480 DateTimeEditElement* edit = dateTimeEditElement();
481 if (valueChanged || (sanitizedValue.isEmpty() && edit && edit->anyEditableFieldsHaveValues())) {
482 updateView();
483 element().setNeedsValidityCheck();
484 }
485 }
486
shouldUseInputMethod() const487 bool BaseMultipleFieldsDateAndTimeInputType::shouldUseInputMethod() const
488 {
489 return false;
490 }
491
stepAttributeChanged()492 void BaseMultipleFieldsDateAndTimeInputType::stepAttributeChanged()
493 {
494 updateView();
495 }
496
updateView()497 void BaseMultipleFieldsDateAndTimeInputType::updateView()
498 {
499 DateTimeEditElement* edit = dateTimeEditElement();
500 if (!edit)
501 return;
502
503 DateTimeEditElement::LayoutParameters layoutParameters(element().locale(), createStepRange(AnyIsDefaultStep));
504
505 DateComponents date;
506 const bool hasValue = parseToDateComponents(element().value(), &date);
507 if (!hasValue)
508 setMillisecondToDateComponents(layoutParameters.stepRange.minimum().toDouble(), &date);
509
510 setupLayoutParameters(layoutParameters, date);
511
512 const AtomicString pattern = edit->fastGetAttribute(HTMLNames::patternAttr);
513 if (!pattern.isEmpty())
514 layoutParameters.dateTimeFormat = pattern;
515
516 if (!DateTimeFormatValidator().validateFormat(layoutParameters.dateTimeFormat, *this))
517 layoutParameters.dateTimeFormat = layoutParameters.fallbackDateTimeFormat;
518
519 if (hasValue)
520 edit->setValueAsDate(layoutParameters, date);
521 else
522 edit->setEmptyValue(layoutParameters, date);
523 updateClearButtonVisibility();
524 }
525
valueAttributeChanged()526 void BaseMultipleFieldsDateAndTimeInputType::valueAttributeChanged()
527 {
528 if (!element().hasDirtyValue())
529 updateView();
530 }
531
listAttributeTargetChanged()532 void BaseMultipleFieldsDateAndTimeInputType::listAttributeTargetChanged()
533 {
534 updatePickerIndicatorVisibility();
535 }
536
updatePickerIndicatorVisibility()537 void BaseMultipleFieldsDateAndTimeInputType::updatePickerIndicatorVisibility()
538 {
539 if (m_pickerIndicatorIsAlwaysVisible) {
540 showPickerIndicator();
541 return;
542 }
543 if (RuntimeEnabledFeatures::dataListElementEnabled()) {
544 if (element().hasValidDataListOptions())
545 showPickerIndicator();
546 else
547 hidePickerIndicator();
548 }
549 }
550
hidePickerIndicator()551 void BaseMultipleFieldsDateAndTimeInputType::hidePickerIndicator()
552 {
553 if (!m_pickerIndicatorIsVisible)
554 return;
555 m_pickerIndicatorIsVisible = false;
556 ASSERT(pickerIndicatorElement());
557 pickerIndicatorElement()->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
558 }
559
showPickerIndicator()560 void BaseMultipleFieldsDateAndTimeInputType::showPickerIndicator()
561 {
562 if (m_pickerIndicatorIsVisible)
563 return;
564 m_pickerIndicatorIsVisible = true;
565 ASSERT(pickerIndicatorElement());
566 pickerIndicatorElement()->removeInlineStyleProperty(CSSPropertyDisplay);
567 }
568
shouldHaveSecondField(const DateComponents & date) const569 bool BaseMultipleFieldsDateAndTimeInputType::shouldHaveSecondField(const DateComponents& date) const
570 {
571 StepRange stepRange = createStepRange(AnyIsDefaultStep);
572 return date.second() || date.millisecond()
573 || !stepRange.minimum().remainder(static_cast<int>(msPerMinute)).isZero()
574 || !stepRange.step().remainder(static_cast<int>(msPerMinute)).isZero();
575 }
576
focusAndSelectClearButtonOwner()577 void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectClearButtonOwner()
578 {
579 element().focus();
580 }
581
shouldClearButtonRespondToMouseEvents()582 bool BaseMultipleFieldsDateAndTimeInputType::shouldClearButtonRespondToMouseEvents()
583 {
584 return !element().isDisabledOrReadOnly() && !element().isRequired();
585 }
586
clearValue()587 void BaseMultipleFieldsDateAndTimeInputType::clearValue()
588 {
589 RefPtr<HTMLInputElement> input(element());
590 input->setValue("", DispatchInputAndChangeEvent);
591 input->updateClearButtonVisibility();
592 }
593
updateClearButtonVisibility()594 void BaseMultipleFieldsDateAndTimeInputType::updateClearButtonVisibility()
595 {
596 ClearButtonElement* clearButton = clearButtonElement();
597 if (!clearButton)
598 return;
599
600 if (element().isRequired() || !dateTimeEditElement()->anyEditableFieldsHaveValues()) {
601 clearButton->setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
602 clearButton->setInlineStyleProperty(CSSPropertyPointerEvents, CSSValueNone);
603 } else {
604 clearButton->removeInlineStyleProperty(CSSPropertyOpacity);
605 clearButton->removeInlineStyleProperty(CSSPropertyPointerEvents);
606 }
607 }
608
609 } // namespace WebCore
610
611 #endif
612