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