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 54 namespace blink { 55 56 class DateTimeFormatValidator : public DateTimeFormat::TokenHandler { 57 public: 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 73 private: 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 84 void 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 123 bool 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 130 DateTimeEditElement* BaseMultipleFieldsDateAndTimeInputType::dateTimeEditElement() const 131 { 132 return toDateTimeEditElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::dateTimeEdit())); 133 } 134 135 SpinButtonElement* BaseMultipleFieldsDateAndTimeInputType::spinButtonElement() const 136 { 137 return toSpinButtonElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::spinButton())); 138 } 139 140 ClearButtonElement* BaseMultipleFieldsDateAndTimeInputType::clearButtonElement() const 141 { 142 return toClearButtonElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::clearButton())); 143 } 144 145 PickerIndicatorElement* BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorElement() const 146 { 147 return toPickerIndicatorElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::pickerIndicator())); 148 } 149 150 inline bool BaseMultipleFieldsDateAndTimeInputType::containsFocusedShadowElement() const 151 { 152 return element().userAgentShadowRoot()->contains(element().document().focusedElement()); 153 } 154 155 void 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 170 void 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 182 void 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 199 bool BaseMultipleFieldsDateAndTimeInputType::hasCustomFocusLogic() const 200 { 201 return false; 202 } 203 204 bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerDisabled() const 205 { 206 return element().isDisabledFormControl(); 207 } 208 209 bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerReadOnly() const 210 { 211 return element().isReadOnly(); 212 } 213 214 void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectSpinButtonOwner() 215 { 216 if (DateTimeEditElement* edit = dateTimeEditElement()) 217 edit->focusIfNoFocus(); 218 } 219 220 bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToMouseEvents() 221 { 222 return !element().isDisabledOrReadOnly(); 223 } 224 225 bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToWheelEvents() 226 { 227 if (!shouldSpinButtonRespondToMouseEvents()) 228 return false; 229 if (DateTimeEditElement* edit = dateTimeEditElement()) 230 return edit->hasFocusedField(); 231 return false; 232 } 233 234 void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepDown() 235 { 236 if (DateTimeEditElement* edit = dateTimeEditElement()) 237 edit->stepDown(); 238 } 239 240 void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepUp() 241 { 242 if (DateTimeEditElement* edit = dateTimeEditElement()) 243 edit->stepUp(); 244 } 245 246 void BaseMultipleFieldsDateAndTimeInputType::spinButtonDidReleaseMouseCapture(SpinButtonElement::EventDispatch eventDispatch) 247 { 248 if (eventDispatch == SpinButtonElement::EventDispatchAllowed) 249 element().dispatchFormControlChangeEvent(); 250 } 251 252 bool BaseMultipleFieldsDateAndTimeInputType::isPickerIndicatorOwnerDisabledOrReadOnly() const 253 { 254 return element().isDisabledOrReadOnly(); 255 } 256 257 void 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 EventQueueScope scope; 268 DateComponents date; 269 unsigned end; 270 if (date.parseDate(value, 0, end) && end == value.length()) 271 edit->setOnlyYearMonthDay(date); 272 element().dispatchFormControlChangeEvent(); 273 } 274 275 void BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorChooseValue(double value) 276 { 277 ASSERT(std::isfinite(value) || std::isnan(value)); 278 if (std::isnan(value)) 279 element().setValue(emptyString(), DispatchInputAndChangeEvent); 280 else 281 element().setValueAsNumber(value, ASSERT_NO_EXCEPTION, DispatchInputAndChangeEvent); 282 } 283 284 Element& BaseMultipleFieldsDateAndTimeInputType::pickerOwnerElement() const 285 { 286 return element(); 287 } 288 289 bool BaseMultipleFieldsDateAndTimeInputType::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters) 290 { 291 return element().setupDateTimeChooserParameters(parameters); 292 } 293 294 BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement& element) 295 : BaseDateAndTimeInputType(element) 296 , m_isDestroyingShadowSubtree(false) 297 , m_pickerIndicatorIsVisible(false) 298 , m_pickerIndicatorIsAlwaysVisible(false) 299 { 300 } 301 302 BaseMultipleFieldsDateAndTimeInputType::~BaseMultipleFieldsDateAndTimeInputType() 303 { 304 #if !ENABLE(OILPAN) 305 if (SpinButtonElement* element = spinButtonElement()) 306 element->removeSpinButtonOwner(); 307 if (ClearButtonElement* element = clearButtonElement()) 308 element->removeClearButtonOwner(); 309 if (DateTimeEditElement* element = dateTimeEditElement()) 310 element->removeEditControlOwner(); 311 if (PickerIndicatorElement* element = pickerIndicatorElement()) 312 element->removePickerIndicatorOwner(); 313 #endif 314 } 315 316 String BaseMultipleFieldsDateAndTimeInputType::badInputText() const 317 { 318 return locale().queryString(blink::WebLocalizedString::ValidationBadInputForDateTime); 319 } 320 321 void BaseMultipleFieldsDateAndTimeInputType::blur() 322 { 323 if (DateTimeEditElement* edit = dateTimeEditElement()) 324 edit->blurByOwner(); 325 } 326 327 PassRefPtr<RenderStyle> BaseMultipleFieldsDateAndTimeInputType::customStyleForRenderer(PassRefPtr<RenderStyle> originalStyle) 328 { 329 EDisplay originalDisplay = originalStyle->display(); 330 EDisplay newDisplay = originalDisplay; 331 if (originalDisplay == INLINE || originalDisplay == INLINE_BLOCK) 332 newDisplay = INLINE_FLEX; 333 else if (originalDisplay == BLOCK) 334 newDisplay = FLEX; 335 TextDirection contentDirection = computedTextDirection(); 336 if (originalStyle->direction() == contentDirection && originalDisplay == newDisplay) 337 return originalStyle; 338 339 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get()); 340 style->setDirection(contentDirection); 341 style->setDisplay(newDisplay); 342 style->setUnique(); 343 return style.release(); 344 } 345 346 void BaseMultipleFieldsDateAndTimeInputType::createShadowSubtree() 347 { 348 ASSERT(element().shadow()); 349 350 // Element must not have a renderer here, because if it did 351 // DateTimeEditElement::customStyleForRenderer() is called in appendChild() 352 // before the field wrapper element is created. 353 // FIXME: This code should not depend on such craziness. 354 ASSERT(!element().renderer()); 355 356 Document& document = element().document(); 357 ContainerNode* container = element().userAgentShadowRoot(); 358 359 container->appendChild(DateTimeEditElement::create(document, *this)); 360 element().updateView(); 361 container->appendChild(ClearButtonElement::create(document, *this)); 362 container->appendChild(SpinButtonElement::create(document, *this)); 363 364 if (RenderTheme::theme().supportsCalendarPicker(formControlType())) 365 m_pickerIndicatorIsAlwaysVisible = true; 366 container->appendChild(PickerIndicatorElement::create(document, *this)); 367 m_pickerIndicatorIsVisible = true; 368 updatePickerIndicatorVisibility(); 369 } 370 371 void BaseMultipleFieldsDateAndTimeInputType::destroyShadowSubtree() 372 { 373 ASSERT(!m_isDestroyingShadowSubtree); 374 m_isDestroyingShadowSubtree = true; 375 if (SpinButtonElement* element = spinButtonElement()) 376 element->removeSpinButtonOwner(); 377 if (ClearButtonElement* element = clearButtonElement()) 378 element->removeClearButtonOwner(); 379 if (DateTimeEditElement* element = dateTimeEditElement()) 380 element->removeEditControlOwner(); 381 if (PickerIndicatorElement* element = pickerIndicatorElement()) 382 element->removePickerIndicatorOwner(); 383 384 // If a field element has focus, set focus back to the <input> itself before 385 // deleting the field. This prevents unnecessary focusout/blur events. 386 if (containsFocusedShadowElement()) 387 element().focus(); 388 389 BaseDateAndTimeInputType::destroyShadowSubtree(); 390 m_isDestroyingShadowSubtree = false; 391 } 392 393 void BaseMultipleFieldsDateAndTimeInputType::handleFocusInEvent(Element* oldFocusedElement, FocusType type) 394 { 395 DateTimeEditElement* edit = dateTimeEditElement(); 396 if (!edit || m_isDestroyingShadowSubtree) 397 return; 398 if (type == FocusTypeBackward) { 399 if (element().document().page()) 400 element().document().page()->focusController().advanceFocus(type); 401 } else if (type == FocusTypeNone || type == FocusTypeMouse || type == FocusTypePage) { 402 edit->focusByOwner(oldFocusedElement); 403 } else { 404 edit->focusByOwner(); 405 } 406 } 407 408 void BaseMultipleFieldsDateAndTimeInputType::forwardEvent(Event* event) 409 { 410 if (SpinButtonElement* element = spinButtonElement()) { 411 element->forwardEvent(event); 412 if (event->defaultHandled()) 413 return; 414 } 415 416 if (DateTimeEditElement* edit = dateTimeEditElement()) 417 edit->defaultEventHandler(event); 418 } 419 420 void BaseMultipleFieldsDateAndTimeInputType::disabledAttributeChanged() 421 { 422 spinButtonElement()->releaseCapture(); 423 clearButtonElement()->releaseCapture(); 424 if (DateTimeEditElement* edit = dateTimeEditElement()) 425 edit->disabledStateChanged(); 426 } 427 428 void BaseMultipleFieldsDateAndTimeInputType::requiredAttributeChanged() 429 { 430 clearButtonElement()->releaseCapture(); 431 updateClearButtonVisibility(); 432 } 433 434 void BaseMultipleFieldsDateAndTimeInputType::handleKeydownEvent(KeyboardEvent* event) 435 { 436 if (m_pickerIndicatorIsVisible 437 && ((event->keyIdentifier() == "Down" && event->getModifierState("Alt")) || (RenderTheme::theme().shouldOpenPickerWithF4Key() && event->keyIdentifier() == "F4"))) { 438 if (PickerIndicatorElement* element = pickerIndicatorElement()) 439 element->openPopup(); 440 event->setDefaultHandled(); 441 } else { 442 forwardEvent(event); 443 } 444 } 445 446 bool BaseMultipleFieldsDateAndTimeInputType::hasBadInput() const 447 { 448 DateTimeEditElement* edit = dateTimeEditElement(); 449 return element().value().isEmpty() && edit && edit->anyEditableFieldsHaveValues(); 450 } 451 452 AtomicString BaseMultipleFieldsDateAndTimeInputType::localeIdentifier() const 453 { 454 return element().computeInheritedLanguage(); 455 } 456 457 void BaseMultipleFieldsDateAndTimeInputType::editControlDidChangeValueByKeyboard() 458 { 459 element().dispatchFormControlChangeEvent(); 460 } 461 462 void BaseMultipleFieldsDateAndTimeInputType::minOrMaxAttributeChanged() 463 { 464 updateView(); 465 } 466 467 void BaseMultipleFieldsDateAndTimeInputType::readonlyAttributeChanged() 468 { 469 spinButtonElement()->releaseCapture(); 470 clearButtonElement()->releaseCapture(); 471 if (DateTimeEditElement* edit = dateTimeEditElement()) 472 edit->readOnlyStateChanged(); 473 } 474 475 void BaseMultipleFieldsDateAndTimeInputType::restoreFormControlState(const FormControlState& state) 476 { 477 DateTimeEditElement* edit = dateTimeEditElement(); 478 if (!edit) 479 return; 480 DateTimeFieldsState dateTimeFieldsState = DateTimeFieldsState::restoreFormControlState(state); 481 edit->setValueAsDateTimeFieldsState(dateTimeFieldsState); 482 element().setValueInternal(sanitizeValue(edit->value()), DispatchNoEvent); 483 updateClearButtonVisibility(); 484 } 485 486 FormControlState BaseMultipleFieldsDateAndTimeInputType::saveFormControlState() const 487 { 488 if (DateTimeEditElement* edit = dateTimeEditElement()) 489 return edit->valueAsDateTimeFieldsState().saveFormControlState(); 490 return FormControlState(); 491 } 492 493 void BaseMultipleFieldsDateAndTimeInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior) 494 { 495 InputType::setValue(sanitizedValue, valueChanged, eventBehavior); 496 DateTimeEditElement* edit = dateTimeEditElement(); 497 if (valueChanged || (sanitizedValue.isEmpty() && edit && edit->anyEditableFieldsHaveValues())) { 498 element().updateView(); 499 element().setNeedsValidityCheck(); 500 } 501 } 502 503 void BaseMultipleFieldsDateAndTimeInputType::stepAttributeChanged() 504 { 505 updateView(); 506 } 507 508 void BaseMultipleFieldsDateAndTimeInputType::updateView() 509 { 510 DateTimeEditElement* edit = dateTimeEditElement(); 511 if (!edit) 512 return; 513 514 DateTimeEditElement::LayoutParameters layoutParameters(element().locale(), createStepRange(AnyIsDefaultStep)); 515 516 DateComponents date; 517 bool hasValue = false; 518 if (!element().suggestedValue().isNull()) 519 hasValue = parseToDateComponents(element().suggestedValue(), &date); 520 else 521 hasValue = parseToDateComponents(element().value(), &date); 522 if (!hasValue) 523 setMillisecondToDateComponents(layoutParameters.stepRange.minimum().toDouble(), &date); 524 525 setupLayoutParameters(layoutParameters, date); 526 527 DEFINE_STATIC_LOCAL(AtomicString, datetimeformatAttr, ("datetimeformat", AtomicString::ConstructFromLiteral)); 528 edit->setAttribute(datetimeformatAttr, AtomicString(layoutParameters.dateTimeFormat), ASSERT_NO_EXCEPTION); 529 const AtomicString pattern = edit->fastGetAttribute(HTMLNames::patternAttr); 530 if (!pattern.isEmpty()) 531 layoutParameters.dateTimeFormat = pattern; 532 533 if (!DateTimeFormatValidator().validateFormat(layoutParameters.dateTimeFormat, *this)) 534 layoutParameters.dateTimeFormat = layoutParameters.fallbackDateTimeFormat; 535 536 if (hasValue) 537 edit->setValueAsDate(layoutParameters, date); 538 else 539 edit->setEmptyValue(layoutParameters, date); 540 updateClearButtonVisibility(); 541 } 542 543 void BaseMultipleFieldsDateAndTimeInputType::valueAttributeChanged() 544 { 545 if (!element().hasDirtyValue()) 546 updateView(); 547 } 548 549 void BaseMultipleFieldsDateAndTimeInputType::listAttributeTargetChanged() 550 { 551 updatePickerIndicatorVisibility(); 552 } 553 554 void BaseMultipleFieldsDateAndTimeInputType::updatePickerIndicatorVisibility() 555 { 556 if (m_pickerIndicatorIsAlwaysVisible) { 557 showPickerIndicator(); 558 return; 559 } 560 if (element().hasValidDataListOptions()) 561 showPickerIndicator(); 562 else 563 hidePickerIndicator(); 564 } 565 566 void BaseMultipleFieldsDateAndTimeInputType::hidePickerIndicator() 567 { 568 if (!m_pickerIndicatorIsVisible) 569 return; 570 m_pickerIndicatorIsVisible = false; 571 ASSERT(pickerIndicatorElement()); 572 pickerIndicatorElement()->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone); 573 } 574 575 void BaseMultipleFieldsDateAndTimeInputType::showPickerIndicator() 576 { 577 if (m_pickerIndicatorIsVisible) 578 return; 579 m_pickerIndicatorIsVisible = true; 580 ASSERT(pickerIndicatorElement()); 581 pickerIndicatorElement()->removeInlineStyleProperty(CSSPropertyDisplay); 582 } 583 584 bool BaseMultipleFieldsDateAndTimeInputType::shouldHaveSecondField(const DateComponents& date) const 585 { 586 StepRange stepRange = createStepRange(AnyIsDefaultStep); 587 return date.second() || date.millisecond() 588 || !stepRange.minimum().remainder(static_cast<int>(msPerMinute)).isZero() 589 || !stepRange.step().remainder(static_cast<int>(msPerMinute)).isZero(); 590 } 591 592 void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectClearButtonOwner() 593 { 594 element().focus(); 595 } 596 597 bool BaseMultipleFieldsDateAndTimeInputType::shouldClearButtonRespondToMouseEvents() 598 { 599 return !element().isDisabledOrReadOnly() && !element().isRequired(); 600 } 601 602 void BaseMultipleFieldsDateAndTimeInputType::clearValue() 603 { 604 RefPtrWillBeRawPtr<HTMLInputElement> input(element()); 605 input->setValue("", DispatchInputAndChangeEvent); 606 input->updateClearButtonVisibility(); 607 } 608 609 void BaseMultipleFieldsDateAndTimeInputType::updateClearButtonVisibility() 610 { 611 ClearButtonElement* clearButton = clearButtonElement(); 612 if (!clearButton) 613 return; 614 615 if (element().isRequired() || !dateTimeEditElement()->anyEditableFieldsHaveValues()) { 616 clearButton->setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER); 617 clearButton->setInlineStyleProperty(CSSPropertyPointerEvents, CSSValueNone); 618 } else { 619 clearButton->removeInlineStyleProperty(CSSPropertyOpacity); 620 clearButton->removeInlineStyleProperty(CSSPropertyPointerEvents); 621 } 622 } 623 624 TextDirection BaseMultipleFieldsDateAndTimeInputType::computedTextDirection() 625 { 626 return element().locale().isRTL() ? RTL : LTR; 627 } 628 629 AXObject* BaseMultipleFieldsDateAndTimeInputType::popupRootAXObject() 630 { 631 if (PickerIndicatorElement* picker = pickerIndicatorElement()) 632 return picker->popupRootAXObject(); 633 return 0; 634 } 635 636 } // namespace blink 637 638 #endif 639