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