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 "config.h" 27 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) 28 #include "core/html/shadow/DateTimeEditElement.h" 29 30 #include "HTMLNames.h" 31 #include "bindings/v8/ExceptionStatePlaceholder.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/rendering/style/RenderStyle.h" 38 #include "core/rendering/style/StyleInheritedData.h" 39 #include "platform/fonts/FontCache.h" 40 #include "platform/text/DateTimeFormat.h" 41 #include "platform/text/PlatformLocale.h" 42 #include "wtf/DateMath.h" 43 44 namespace WebCore { 45 46 using namespace HTMLNames; 47 using namespace WTF::Unicode; 48 49 class DateTimeEditBuilder : private DateTimeFormat::TokenHandler { 50 WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder); 51 52 public: 53 // The argument objects must be alive until this object dies. 54 DateTimeEditBuilder(DateTimeEditElement&, const DateTimeEditElement::LayoutParameters&, 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& stepRange() const { return m_parameters.stepRange; } 68 DateTimeNumericFieldElement::Step createStep(double msPerFieldUnit, double msPerFieldSize) const; 69 70 // DateTimeFormat::TokenHandler functions. 71 virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL; 72 virtual void visitLiteral(const String&) OVERRIDE FINAL; 73 74 DateTimeEditElement& m_editElement; 75 const DateComponents m_dateValue; 76 const DateTimeEditElement::LayoutParameters& m_parameters; 77 DateTimeNumericFieldElement::Range m_dayRange; 78 DateTimeNumericFieldElement::Range m_hour23Range; 79 DateTimeNumericFieldElement::Range m_minuteRange; 80 DateTimeNumericFieldElement::Range m_secondRange; 81 DateTimeNumericFieldElement::Range m_millisecondRange; 82 }; 83 84 DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& dateValue) 85 : m_editElement(elemnt) 86 , m_dateValue(dateValue) 87 , m_parameters(layoutParameters) 88 , m_dayRange(1, 31) 89 , m_hour23Range(0, 23) 90 , m_minuteRange(0, 59) 91 , m_secondRange(0, 59) 92 , m_millisecondRange(0, 999) 93 { 94 if (m_dateValue.type() == DateComponents::Date || m_dateValue.type() == DateComponents::DateTimeLocal) { 95 if (m_parameters.minimum.type() != DateComponents::Invalid 96 && m_parameters.maximum.type() != DateComponents::Invalid 97 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear() 98 && m_parameters.minimum.month() == m_parameters.maximum.month() 99 && m_parameters.minimum.monthDay() <= m_parameters.maximum.monthDay()) { 100 m_dayRange.minimum = m_parameters.minimum.monthDay(); 101 m_dayRange.maximum = m_parameters.maximum.monthDay(); 102 } 103 } 104 105 if (m_dateValue.type() == DateComponents::Time || m_dayRange.isSingleton()) { 106 if (m_parameters.minimum.type() != DateComponents::Invalid 107 && m_parameters.maximum.type() != DateComponents::Invalid 108 && m_parameters.minimum.hour() <= m_parameters.maximum.hour()) { 109 m_hour23Range.minimum = m_parameters.minimum.hour(); 110 m_hour23Range.maximum = m_parameters.maximum.hour(); 111 } 112 } 113 114 if (m_hour23Range.isSingleton() && m_parameters.minimum.minute() <= m_parameters.maximum.minute()) { 115 m_minuteRange.minimum = m_parameters.minimum.minute(); 116 m_minuteRange.maximum = m_parameters.maximum.minute(); 117 } 118 if (m_minuteRange.isSingleton() && m_parameters.minimum.second() <= m_parameters.maximum.second()) { 119 m_secondRange.minimum = m_parameters.minimum.second(); 120 m_secondRange.maximum = m_parameters.maximum.second(); 121 } 122 if (m_secondRange.isSingleton() && m_parameters.minimum.millisecond() <= m_parameters.maximum.millisecond()) { 123 m_millisecondRange.minimum = m_parameters.minimum.millisecond(); 124 m_millisecondRange.maximum = m_parameters.maximum.millisecond(); 125 } 126 } 127 128 bool DateTimeEditBuilder::build(const String& formatString) 129 { 130 m_editElement.resetFields(); 131 return DateTimeFormat::parse(formatString, *this); 132 } 133 134 bool DateTimeEditBuilder::needMillisecondField() const 135 { 136 return m_dateValue.millisecond() 137 || !stepRange().minimum().remainder(static_cast<int>(msPerSecond)).isZero() 138 || !stepRange().step().remainder(static_cast<int>(msPerSecond)).isZero(); 139 } 140 141 void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int count) 142 { 143 const int countForAbbreviatedMonth = 3; 144 const int countForFullMonth = 4; 145 const int countForNarrowMonth = 5; 146 Document& document = m_editElement.document(); 147 148 switch (fieldType) { 149 case DateTimeFormat::FieldTypeDayOfMonth: { 150 RefPtr<DateTimeFieldElement> field = DateTimeDayFieldElement::create(document, m_editElement, m_parameters.placeholderForDay, m_dayRange); 151 m_editElement.addField(field); 152 if (shouldDayOfMonthFieldDisabled()) { 153 field->setValueAsDate(m_dateValue); 154 field->setDisabled(); 155 } 156 return; 157 } 158 159 case DateTimeFormat::FieldTypeHour11: { 160 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12); 161 RefPtr<DateTimeFieldElement> field = DateTimeHour11FieldElement::create(document, m_editElement, m_hour23Range, step); 162 m_editElement.addField(field); 163 if (shouldHourFieldDisabled()) { 164 field->setValueAsDate(m_dateValue); 165 field->setDisabled(); 166 } 167 return; 168 } 169 170 case DateTimeFormat::FieldTypeHour12: { 171 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12); 172 RefPtr<DateTimeFieldElement> field = DateTimeHour12FieldElement::create(document, m_editElement, m_hour23Range, step); 173 m_editElement.addField(field); 174 if (shouldHourFieldDisabled()) { 175 field->setValueAsDate(m_dateValue); 176 field->setDisabled(); 177 } 178 return; 179 } 180 181 case DateTimeFormat::FieldTypeHour23: { 182 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay); 183 RefPtr<DateTimeFieldElement> field = DateTimeHour23FieldElement::create(document, m_editElement, m_hour23Range, step); 184 m_editElement.addField(field); 185 if (shouldHourFieldDisabled()) { 186 field->setValueAsDate(m_dateValue); 187 field->setDisabled(); 188 } 189 return; 190 } 191 192 case DateTimeFormat::FieldTypeHour24: { 193 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay); 194 RefPtr<DateTimeFieldElement> field = DateTimeHour24FieldElement::create(document, m_editElement, m_hour23Range, step); 195 m_editElement.addField(field); 196 if (shouldHourFieldDisabled()) { 197 field->setValueAsDate(m_dateValue); 198 field->setDisabled(); 199 } 200 return; 201 } 202 203 case DateTimeFormat::FieldTypeMinute: { 204 DateTimeNumericFieldElement::Step step = createStep(msPerMinute, msPerHour); 205 RefPtr<DateTimeNumericFieldElement> field = DateTimeMinuteFieldElement::create(document, m_editElement, m_minuteRange, step); 206 m_editElement.addField(field); 207 if (shouldMinuteFieldDisabled()) { 208 field->setValueAsDate(m_dateValue); 209 field->setDisabled(); 210 } 211 return; 212 } 213 214 case DateTimeFormat::FieldTypeMonth: // Fallthrough. 215 case DateTimeFormat::FieldTypeMonthStandAlone: { 216 int minMonth = 0, maxMonth = 11; 217 if (m_parameters.minimum.type() != DateComponents::Invalid 218 && m_parameters.maximum.type() != DateComponents::Invalid 219 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear() 220 && m_parameters.minimum.month() <= m_parameters.maximum.month()) { 221 minMonth = m_parameters.minimum.month(); 222 maxMonth = m_parameters.maximum.month(); 223 } 224 RefPtr<DateTimeFieldElement> field; 225 switch (count) { 226 case countForNarrowMonth: // Fallthrough. 227 case countForAbbreviatedMonth: 228 field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.shortMonthLabels() : m_parameters.locale.shortStandAloneMonthLabels(), minMonth, maxMonth); 229 break; 230 case countForFullMonth: 231 field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.monthLabels() : m_parameters.locale.standAloneMonthLabels(), minMonth, maxMonth); 232 break; 233 default: 234 field = DateTimeMonthFieldElement::create(document, m_editElement, m_parameters.placeholderForMonth, DateTimeNumericFieldElement::Range(minMonth + 1, maxMonth + 1)); 235 break; 236 } 237 m_editElement.addField(field); 238 if (minMonth == maxMonth && minMonth == m_dateValue.month() && m_dateValue.type() != DateComponents::Month) { 239 field->setValueAsDate(m_dateValue); 240 field->setDisabled(); 241 } 242 return; 243 } 244 245 case DateTimeFormat::FieldTypePeriod: { 246 RefPtr<DateTimeFieldElement> field = DateTimeAMPMFieldElement::create(document, m_editElement, m_parameters.locale.timeAMPMLabels()); 247 m_editElement.addField(field); 248 if (shouldAMPMFieldDisabled()) { 249 field->setValueAsDate(m_dateValue); 250 field->setDisabled(); 251 } 252 return; 253 } 254 255 case DateTimeFormat::FieldTypeSecond: { 256 DateTimeNumericFieldElement::Step step = createStep(msPerSecond, msPerMinute); 257 RefPtr<DateTimeNumericFieldElement> field = DateTimeSecondFieldElement::create(document, m_editElement, m_secondRange, step); 258 m_editElement.addField(field); 259 if (shouldSecondFieldDisabled()) { 260 field->setValueAsDate(m_dateValue); 261 field->setDisabled(); 262 } 263 264 if (needMillisecondField()) { 265 visitLiteral(m_parameters.locale.localizedDecimalSeparator()); 266 visitField(DateTimeFormat::FieldTypeFractionalSecond, 3); 267 } 268 return; 269 } 270 271 case DateTimeFormat::FieldTypeFractionalSecond: { 272 DateTimeNumericFieldElement::Step step = createStep(1, msPerSecond); 273 RefPtr<DateTimeNumericFieldElement> field = DateTimeMillisecondFieldElement::create(document, m_editElement, m_millisecondRange, step); 274 m_editElement.addField(field); 275 if (shouldMillisecondFieldDisabled()) { 276 field->setValueAsDate(m_dateValue); 277 field->setDisabled(); 278 } 279 return; 280 } 281 282 case DateTimeFormat::FieldTypeWeekOfYear: { 283 DateTimeNumericFieldElement::Range range(DateComponents::minimumWeekNumber, DateComponents::maximumWeekNumber); 284 if (m_parameters.minimum.type() != DateComponents::Invalid 285 && m_parameters.maximum.type() != DateComponents::Invalid 286 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear() 287 && m_parameters.minimum.week() <= m_parameters.maximum.week()) { 288 range.minimum = m_parameters.minimum.week(); 289 range.maximum = m_parameters.maximum.week(); 290 } 291 m_editElement.addField(DateTimeWeekFieldElement::create(document, m_editElement, range)); 292 return; 293 } 294 295 case DateTimeFormat::FieldTypeYear: { 296 DateTimeYearFieldElement::Parameters yearParams; 297 if (m_parameters.minimum.type() == DateComponents::Invalid) { 298 yearParams.minimumYear = DateComponents::minimumYear(); 299 yearParams.minIsSpecified = false; 300 } else { 301 yearParams.minimumYear = m_parameters.minimum.fullYear(); 302 yearParams.minIsSpecified = true; 303 } 304 if (m_parameters.maximum.type() == DateComponents::Invalid) { 305 yearParams.maximumYear = DateComponents::maximumYear(); 306 yearParams.maxIsSpecified = false; 307 } else { 308 yearParams.maximumYear = m_parameters.maximum.fullYear(); 309 yearParams.maxIsSpecified = true; 310 } 311 if (yearParams.minimumYear > yearParams.maximumYear) { 312 std::swap(yearParams.minimumYear, yearParams.maximumYear); 313 std::swap(yearParams.minIsSpecified, yearParams.maxIsSpecified); 314 } 315 yearParams.placeholder = m_parameters.placeholderForYear; 316 RefPtr<DateTimeFieldElement> field = DateTimeYearFieldElement::create(document, m_editElement, yearParams); 317 m_editElement.addField(field); 318 if (shouldYearFieldDisabled()) { 319 field->setValueAsDate(m_dateValue); 320 field->setDisabled(); 321 } 322 return; 323 } 324 325 default: 326 return; 327 } 328 } 329 330 bool DateTimeEditBuilder::shouldAMPMFieldDisabled() const 331 { 332 return shouldHourFieldDisabled() 333 || (m_hour23Range.minimum < 12 && m_hour23Range.maximum < 12 && m_dateValue.hour() < 12) 334 || (m_hour23Range.minimum >= 12 && m_hour23Range.maximum >= 12 && m_dateValue.hour() >= 12); 335 } 336 337 bool DateTimeEditBuilder::shouldDayOfMonthFieldDisabled() const 338 { 339 return m_dayRange.isSingleton() && m_dayRange.minimum == m_dateValue.monthDay() && m_dateValue.type() != DateComponents::Date; 340 } 341 342 bool DateTimeEditBuilder::shouldHourFieldDisabled() const 343 { 344 if (m_hour23Range.isSingleton() && m_hour23Range.minimum == m_dateValue.hour() 345 && !(shouldMinuteFieldDisabled() && shouldSecondFieldDisabled() && shouldMillisecondFieldDisabled())) 346 return true; 347 348 if (m_dateValue.type() == DateComponents::Time) 349 return false; 350 ASSERT(m_dateValue.type() == DateComponents::DateTimeLocal); 351 352 if (shouldDayOfMonthFieldDisabled()) { 353 ASSERT(m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()); 354 ASSERT(m_parameters.minimum.month() == m_parameters.maximum.month()); 355 return false; 356 } 357 358 const Decimal decimalMsPerDay(static_cast<int>(msPerDay)); 359 Decimal hourPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerDay) / static_cast<int>(msPerHour)).floor(); 360 return hourPartOfMinimum == m_dateValue.hour() && stepRange().step().remainder(decimalMsPerDay).isZero(); 361 } 362 363 bool DateTimeEditBuilder::shouldMillisecondFieldDisabled() const 364 { 365 if (m_millisecondRange.isSingleton() && m_millisecondRange.minimum == m_dateValue.millisecond()) 366 return true; 367 368 const Decimal decimalMsPerSecond(static_cast<int>(msPerSecond)); 369 return stepRange().minimum().abs().remainder(decimalMsPerSecond) == m_dateValue.millisecond() && stepRange().step().remainder(decimalMsPerSecond).isZero(); 370 } 371 372 bool DateTimeEditBuilder::shouldMinuteFieldDisabled() const 373 { 374 if (m_minuteRange.isSingleton() && m_minuteRange.minimum == m_dateValue.minute()) 375 return true; 376 377 const Decimal decimalMsPerHour(static_cast<int>(msPerHour)); 378 Decimal minutePartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerHour) / static_cast<int>(msPerMinute)).floor(); 379 return minutePartOfMinimum == m_dateValue.minute() && stepRange().step().remainder(decimalMsPerHour).isZero(); 380 } 381 382 bool DateTimeEditBuilder::shouldSecondFieldDisabled() const 383 { 384 if (m_secondRange.isSingleton() && m_secondRange.minimum == m_dateValue.second()) 385 return true; 386 387 const Decimal decimalMsPerMinute(static_cast<int>(msPerMinute)); 388 Decimal secondPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerMinute) / static_cast<int>(msPerSecond)).floor(); 389 return secondPartOfMinimum == m_dateValue.second() && stepRange().step().remainder(decimalMsPerMinute).isZero(); 390 } 391 392 bool DateTimeEditBuilder::shouldYearFieldDisabled() const 393 { 394 return m_parameters.minimum.type() != DateComponents::Invalid 395 && m_parameters.maximum.type() != DateComponents::Invalid 396 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear() 397 && m_parameters.minimum.fullYear() == m_dateValue.fullYear(); 398 } 399 400 void DateTimeEditBuilder::visitLiteral(const String& text) 401 { 402 DEFINE_STATIC_LOCAL(AtomicString, textPseudoId, ("-webkit-datetime-edit-text", AtomicString::ConstructFromLiteral)); 403 ASSERT(text.length()); 404 RefPtr<HTMLDivElement> element = HTMLDivElement::create(m_editElement.document()); 405 element->setPseudo(textPseudoId); 406 if (m_parameters.locale.isRTL() && text.length()) { 407 Direction dir = direction(text[0]); 408 if (dir == SegmentSeparator || dir == WhiteSpaceNeutral || dir == OtherNeutral) 409 element->appendChild(Text::create(m_editElement.document(), String(&rightToLeftMark, 1))); 410 } 411 element->appendChild(Text::create(m_editElement.document(), text)); 412 m_editElement.fieldsWrapperElement()->appendChild(element); 413 } 414 415 DateTimeNumericFieldElement::Step DateTimeEditBuilder::createStep(double msPerFieldUnit, double msPerFieldSize) const 416 { 417 const Decimal msPerFieldUnitDecimal(static_cast<int>(msPerFieldUnit)); 418 const Decimal msPerFieldSizeDecimal(static_cast<int>(msPerFieldSize)); 419 Decimal stepMilliseconds = stepRange().step(); 420 ASSERT(!msPerFieldUnitDecimal.isZero()); 421 ASSERT(!msPerFieldSizeDecimal.isZero()); 422 ASSERT(!stepMilliseconds.isZero()); 423 424 DateTimeNumericFieldElement::Step step(1, 0); 425 426 if (stepMilliseconds.remainder(msPerFieldSizeDecimal).isZero()) 427 stepMilliseconds = msPerFieldSizeDecimal; 428 429 if (msPerFieldSizeDecimal.remainder(stepMilliseconds).isZero() && stepMilliseconds.remainder(msPerFieldUnitDecimal).isZero()) { 430 step.step = static_cast<int>((stepMilliseconds / msPerFieldUnitDecimal).toDouble()); 431 step.stepBase = static_cast<int>((stepRange().stepBase() / msPerFieldUnitDecimal).floor().remainder(msPerFieldSizeDecimal / msPerFieldUnitDecimal).toDouble()); 432 } 433 return step; 434 } 435 436 // ---------------------------- 437 438 DateTimeEditElement::EditControlOwner::~EditControlOwner() 439 { 440 } 441 442 DateTimeEditElement::DateTimeEditElement(Document& document, EditControlOwner& editControlOwner) 443 : HTMLDivElement(document) 444 , m_editControlOwner(&editControlOwner) 445 { 446 setHasCustomStyleCallbacks(); 447 } 448 449 DateTimeEditElement::~DateTimeEditElement() 450 { 451 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 452 m_fields[fieldIndex]->removeEventHandler(); 453 } 454 455 inline Element* DateTimeEditElement::fieldsWrapperElement() const 456 { 457 ASSERT(firstChild()); 458 return toElement(firstChild()); 459 } 460 461 void DateTimeEditElement::addField(PassRefPtr<DateTimeFieldElement> field) 462 { 463 if (m_fields.size() == m_fields.capacity()) 464 return; 465 m_fields.append(field.get()); 466 fieldsWrapperElement()->appendChild(field); 467 } 468 469 bool DateTimeEditElement::anyEditableFieldsHaveValues() const 470 { 471 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { 472 if (!m_fields[fieldIndex]->isDisabled() && m_fields[fieldIndex]->hasValue()) 473 return true; 474 } 475 return false; 476 } 477 478 void DateTimeEditElement::blurByOwner() 479 { 480 if (DateTimeFieldElement* field = focusedField()) 481 field->blur(); 482 } 483 484 PassRefPtr<DateTimeEditElement> DateTimeEditElement::create(Document& document, EditControlOwner& editControlOwner) 485 { 486 RefPtr<DateTimeEditElement> container = adoptRef(new DateTimeEditElement(document, editControlOwner)); 487 container->setPseudo(AtomicString("-webkit-datetime-edit", AtomicString::ConstructFromLiteral)); 488 container->setAttribute(idAttr, ShadowElementNames::dateTimeEdit()); 489 return container.release(); 490 } 491 492 PassRefPtr<RenderStyle> DateTimeEditElement::customStyleForRenderer() 493 { 494 // FIXME: This is a kind of layout. We might want to introduce new renderer. 495 FontCachePurgePreventer fontCachePurgePreventer; 496 RefPtr<RenderStyle> originalStyle = originalStyleForRenderer(); 497 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get()); 498 float width = 0; 499 for (Node* child = fieldsWrapperElement()->firstChild(); child; child = child->nextSibling()) { 500 if (!child->isElementNode()) 501 continue; 502 Element* childElement = toElement(child); 503 if (childElement->isDateTimeFieldElement()) { 504 // We need to pass the Font of this element because child elements 505 // can't resolve inherited style at this timing. 506 width += static_cast<DateTimeFieldElement*>(childElement)->maximumWidth(style->font()); 507 } else { 508 // ::-webkit-datetime-edit-text case. It has no 509 // border/padding/margin in html.css. 510 width += style->font().width(childElement->textContent()); 511 } 512 } 513 style->setWidth(Length(ceilf(width), Fixed)); 514 style->setUnique(); 515 return style.release(); 516 } 517 518 void DateTimeEditElement::didBlurFromField() 519 { 520 if (m_editControlOwner) 521 m_editControlOwner->didBlurFromControl(); 522 } 523 524 void DateTimeEditElement::didFocusOnField() 525 { 526 if (m_editControlOwner) 527 m_editControlOwner->didFocusOnControl(); 528 } 529 530 void DateTimeEditElement::disabledStateChanged() 531 { 532 updateUIState(); 533 } 534 535 DateTimeFieldElement* DateTimeEditElement::fieldAt(size_t fieldIndex) const 536 { 537 return fieldIndex < m_fields.size() ? m_fields[fieldIndex] : 0; 538 } 539 540 size_t DateTimeEditElement::fieldIndexOf(const DateTimeFieldElement& field) const 541 { 542 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { 543 if (m_fields[fieldIndex] == &field) 544 return fieldIndex; 545 } 546 return invalidFieldIndex; 547 } 548 549 void DateTimeEditElement::focusIfNoFocus() 550 { 551 if (focusedFieldIndex() != invalidFieldIndex) 552 return; 553 focusOnNextFocusableField(0); 554 } 555 556 void DateTimeEditElement::focusByOwner(Element* oldFocusedElement) 557 { 558 if (oldFocusedElement && oldFocusedElement->isDateTimeFieldElement()) { 559 DateTimeFieldElement* oldFocusedField = static_cast<DateTimeFieldElement*>(oldFocusedElement); 560 size_t index = fieldIndexOf(*oldFocusedField); 561 if (index != invalidFieldIndex && oldFocusedField->isFocusable()) { 562 oldFocusedField->focus(); 563 return; 564 } 565 } 566 focusOnNextFocusableField(0); 567 } 568 569 DateTimeFieldElement* DateTimeEditElement::focusedField() const 570 { 571 return fieldAt(focusedFieldIndex()); 572 } 573 574 size_t DateTimeEditElement::focusedFieldIndex() const 575 { 576 Element* const focusedFieldElement = document().focusedElement(); 577 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { 578 if (m_fields[fieldIndex] == focusedFieldElement) 579 return fieldIndex; 580 } 581 return invalidFieldIndex; 582 } 583 584 void DateTimeEditElement::fieldValueChanged() 585 { 586 if (m_editControlOwner) 587 m_editControlOwner->editControlValueChanged(); 588 } 589 590 bool DateTimeEditElement::focusOnNextFocusableField(size_t startIndex) 591 { 592 for (size_t fieldIndex = startIndex; fieldIndex < m_fields.size(); ++fieldIndex) { 593 if (m_fields[fieldIndex]->isFocusable()) { 594 m_fields[fieldIndex]->focus(); 595 return true; 596 } 597 } 598 return false; 599 } 600 601 bool DateTimeEditElement::focusOnNextField(const DateTimeFieldElement& field) 602 { 603 const size_t startFieldIndex = fieldIndexOf(field); 604 if (startFieldIndex == invalidFieldIndex) 605 return false; 606 return focusOnNextFocusableField(startFieldIndex + 1); 607 } 608 609 bool DateTimeEditElement::focusOnPreviousField(const DateTimeFieldElement& field) 610 { 611 const size_t startFieldIndex = fieldIndexOf(field); 612 if (startFieldIndex == invalidFieldIndex) 613 return false; 614 size_t fieldIndex = startFieldIndex; 615 while (fieldIndex > 0) { 616 --fieldIndex; 617 if (m_fields[fieldIndex]->isFocusable()) { 618 m_fields[fieldIndex]->focus(); 619 return true; 620 } 621 } 622 return false; 623 } 624 625 bool DateTimeEditElement::isDateTimeEditElement() const 626 { 627 return true; 628 } 629 630 bool DateTimeEditElement::isDisabled() const 631 { 632 return m_editControlOwner && m_editControlOwner->isEditControlOwnerDisabled(); 633 } 634 635 bool DateTimeEditElement::isFieldOwnerDisabled() const 636 { 637 return isDisabled(); 638 } 639 640 bool DateTimeEditElement::isFieldOwnerReadOnly() const 641 { 642 return isReadOnly(); 643 } 644 645 bool DateTimeEditElement::isReadOnly() const 646 { 647 return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly(); 648 } 649 650 void DateTimeEditElement::layout(const LayoutParameters& layoutParameters, const DateComponents& dateValue) 651 { 652 DEFINE_STATIC_LOCAL(AtomicString, fieldsWrapperPseudoId, ("-webkit-datetime-edit-fields-wrapper", AtomicString::ConstructFromLiteral)); 653 if (!firstChild()) { 654 RefPtr<HTMLDivElement> element = HTMLDivElement::create(document()); 655 element->setPseudo(fieldsWrapperPseudoId); 656 appendChild(element.get()); 657 } 658 Element* fieldsWrapper = fieldsWrapperElement(); 659 660 size_t focusedFieldIndex = this->focusedFieldIndex(); 661 DateTimeFieldElement* const focusedField = fieldAt(focusedFieldIndex); 662 const AtomicString focusedFieldId = focusedField ? focusedField->shadowPseudoId() : nullAtom; 663 664 DateTimeEditBuilder builder(*this, layoutParameters, dateValue); 665 Node* lastChildToBeRemoved = fieldsWrapper->lastChild(); 666 if (!builder.build(layoutParameters.dateTimeFormat) || m_fields.isEmpty()) { 667 lastChildToBeRemoved = fieldsWrapper->lastChild(); 668 builder.build(layoutParameters.fallbackDateTimeFormat); 669 } 670 671 if (focusedFieldIndex != invalidFieldIndex) { 672 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { 673 if (m_fields[fieldIndex]->shadowPseudoId() == focusedFieldId) { 674 focusedFieldIndex = fieldIndex; 675 break; 676 } 677 } 678 if (DateTimeFieldElement* field = fieldAt(std::min(focusedFieldIndex, m_fields.size() - 1))) 679 field->focus(); 680 } 681 682 if (lastChildToBeRemoved) { 683 for (Node* childNode = fieldsWrapper->firstChild(); childNode; childNode = fieldsWrapper->firstChild()) { 684 fieldsWrapper->removeChild(childNode); 685 if (childNode == lastChildToBeRemoved) 686 break; 687 } 688 setNeedsStyleRecalc(); 689 } 690 } 691 692 AtomicString DateTimeEditElement::localeIdentifier() const 693 { 694 return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom; 695 } 696 697 void DateTimeEditElement::readOnlyStateChanged() 698 { 699 updateUIState(); 700 } 701 702 void DateTimeEditElement::resetFields() 703 { 704 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 705 m_fields[fieldIndex]->removeEventHandler(); 706 m_fields.shrink(0); 707 } 708 709 void DateTimeEditElement::defaultEventHandler(Event* event) 710 { 711 // In case of control owner forward event to control, e.g. DOM 712 // dispatchEvent method. 713 if (DateTimeFieldElement* field = focusedField()) { 714 field->defaultEventHandler(event); 715 if (event->defaultHandled()) 716 return; 717 } 718 719 HTMLDivElement::defaultEventHandler(event); 720 } 721 722 void DateTimeEditElement::setValueAsDate(const LayoutParameters& layoutParameters, const DateComponents& date) 723 { 724 layout(layoutParameters, date); 725 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 726 m_fields[fieldIndex]->setValueAsDate(date); 727 } 728 729 void DateTimeEditElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) 730 { 731 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 732 m_fields[fieldIndex]->setValueAsDateTimeFieldsState(dateTimeFieldsState); 733 } 734 735 void DateTimeEditElement::setEmptyValue(const LayoutParameters& layoutParameters, const DateComponents& dateForReadOnlyField) 736 { 737 layout(layoutParameters, dateForReadOnlyField); 738 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 739 m_fields[fieldIndex]->setEmptyValue(DateTimeFieldElement::DispatchNoEvent); 740 } 741 742 bool DateTimeEditElement::hasFocusedField() 743 { 744 return focusedFieldIndex() != invalidFieldIndex; 745 } 746 747 void DateTimeEditElement::setOnlyYearMonthDay(const DateComponents& date) 748 { 749 ASSERT(date.type() == DateComponents::Date); 750 751 if (!m_editControlOwner) 752 return; 753 754 DateTimeFieldsState dateTimeFieldsState = valueAsDateTimeFieldsState(); 755 dateTimeFieldsState.setYear(date.fullYear()); 756 dateTimeFieldsState.setMonth(date.month() + 1); 757 dateTimeFieldsState.setDayOfMonth(date.monthDay()); 758 setValueAsDateTimeFieldsState(dateTimeFieldsState); 759 m_editControlOwner->editControlValueChanged(); 760 } 761 762 void DateTimeEditElement::stepDown() 763 { 764 if (DateTimeFieldElement* const field = focusedField()) 765 field->stepDown(); 766 } 767 768 void DateTimeEditElement::stepUp() 769 { 770 if (DateTimeFieldElement* const field = focusedField()) 771 field->stepUp(); 772 } 773 774 void DateTimeEditElement::updateUIState() 775 { 776 if (isDisabled()) { 777 if (DateTimeFieldElement* field = focusedField()) 778 field->blur(); 779 } 780 } 781 782 String DateTimeEditElement::value() const 783 { 784 if (!m_editControlOwner) 785 return emptyString(); 786 return m_editControlOwner->formatDateTimeFieldsState(valueAsDateTimeFieldsState()); 787 } 788 789 DateTimeFieldsState DateTimeEditElement::valueAsDateTimeFieldsState() const 790 { 791 DateTimeFieldsState dateTimeFieldsState; 792 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 793 m_fields[fieldIndex]->populateDateTimeFieldsState(dateTimeFieldsState); 794 return dateTimeFieldsState; 795 } 796 797 } // namespace WebCore 798 799 #endif 800