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/MouseEvent.h" 33 #include "core/dom/Text.h" 34 #include "core/html/DateTimeFieldsState.h" 35 #include "core/html/shadow/DateTimeFieldElements.h" 36 #include "core/html/shadow/ShadowElementNames.h" 37 #include "core/platform/DateComponents.h" 38 #include "core/platform/graphics/FontCache.h" 39 #include "core/platform/text/DateTimeFormat.h" 40 #include "core/platform/text/PlatformLocale.h" 41 #include "core/rendering/style/RenderStyle.h" 42 #include "core/rendering/style/StyleInheritedData.h" 43 #include "wtf/DateMath.h" 44 45 namespace WebCore { 46 47 using namespace HTMLNames; 48 using namespace WTF::Unicode; 49 50 class DateTimeEditBuilder : private DateTimeFormat::TokenHandler { 51 WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder); 52 53 public: 54 // The argument objects must be alive until this object dies. 55 DateTimeEditBuilder(DateTimeEditElement&, const DateTimeEditElement::LayoutParameters&, const DateComponents&); 56 57 bool build(const String&); 58 59 private: 60 bool needMillisecondField() const; 61 bool shouldAMPMFieldDisabled() const; 62 bool shouldDayOfMonthFieldDisabled() const; 63 bool shouldHourFieldDisabled() const; 64 bool shouldMillisecondFieldDisabled() const; 65 bool shouldMinuteFieldDisabled() const; 66 bool shouldSecondFieldDisabled() const; 67 bool shouldYearFieldDisabled() const; 68 inline const StepRange& stepRange() const { return m_parameters.stepRange; } 69 DateTimeNumericFieldElement::Step createStep(double msPerFieldUnit, double msPerFieldSize) const; 70 71 // DateTimeFormat::TokenHandler functions. 72 virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL; 73 virtual void visitLiteral(const String&) OVERRIDE FINAL; 74 75 DateTimeEditElement& m_editElement; 76 const DateComponents m_dateValue; 77 const DateTimeEditElement::LayoutParameters& m_parameters; 78 DateTimeNumericFieldElement::Range m_dayRange; 79 DateTimeNumericFieldElement::Range m_hour23Range; 80 DateTimeNumericFieldElement::Range m_minuteRange; 81 DateTimeNumericFieldElement::Range m_secondRange; 82 DateTimeNumericFieldElement::Range m_millisecondRange; 83 }; 84 85 DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& dateValue) 86 : m_editElement(elemnt) 87 , m_dateValue(dateValue) 88 , m_parameters(layoutParameters) 89 , m_dayRange(1, 31) 90 , m_hour23Range(0, 23) 91 , m_minuteRange(0, 59) 92 , m_secondRange(0, 59) 93 , m_millisecondRange(0, 999) 94 { 95 if (m_dateValue.type() == DateComponents::Date || m_dateValue.type() == DateComponents::DateTimeLocal) { 96 if (m_parameters.minimum.type() != DateComponents::Invalid 97 && m_parameters.maximum.type() != DateComponents::Invalid 98 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear() 99 && m_parameters.minimum.month() == m_parameters.maximum.month() 100 && m_parameters.minimum.monthDay() <= m_parameters.maximum.monthDay()) { 101 m_dayRange.minimum = m_parameters.minimum.monthDay(); 102 m_dayRange.maximum = m_parameters.maximum.monthDay(); 103 } 104 } 105 106 if (m_dateValue.type() == DateComponents::Time || m_dayRange.isSingleton()) { 107 if (m_parameters.minimum.type() != DateComponents::Invalid 108 && m_parameters.maximum.type() != DateComponents::Invalid 109 && m_parameters.minimum.hour() <= m_parameters.maximum.hour()) { 110 m_hour23Range.minimum = m_parameters.minimum.hour(); 111 m_hour23Range.maximum = m_parameters.maximum.hour(); 112 } 113 } 114 115 if (m_hour23Range.isSingleton() && m_parameters.minimum.minute() <= m_parameters.maximum.minute()) { 116 m_minuteRange.minimum = m_parameters.minimum.minute(); 117 m_minuteRange.maximum = m_parameters.maximum.minute(); 118 } 119 if (m_minuteRange.isSingleton() && m_parameters.minimum.second() <= m_parameters.maximum.second()) { 120 m_secondRange.minimum = m_parameters.minimum.second(); 121 m_secondRange.maximum = m_parameters.maximum.second(); 122 } 123 if (m_secondRange.isSingleton() && m_parameters.minimum.millisecond() <= m_parameters.maximum.millisecond()) { 124 m_millisecondRange.minimum = m_parameters.minimum.millisecond(); 125 m_millisecondRange.maximum = m_parameters.maximum.millisecond(); 126 } 127 } 128 129 bool DateTimeEditBuilder::build(const String& formatString) 130 { 131 m_editElement.resetFields(); 132 return DateTimeFormat::parse(formatString, *this); 133 } 134 135 bool DateTimeEditBuilder::needMillisecondField() const 136 { 137 return m_dateValue.millisecond() 138 || !stepRange().minimum().remainder(static_cast<int>(msPerSecond)).isZero() 139 || !stepRange().step().remainder(static_cast<int>(msPerSecond)).isZero(); 140 } 141 142 void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int count) 143 { 144 const int countForAbbreviatedMonth = 3; 145 const int countForFullMonth = 4; 146 const int countForNarrowMonth = 5; 147 Document* const document = m_editElement.document(); 148 149 switch (fieldType) { 150 case DateTimeFormat::FieldTypeDayOfMonth: { 151 RefPtr<DateTimeFieldElement> field = DateTimeDayFieldElement::create(document, m_editElement, m_parameters.placeholderForDay, m_dayRange); 152 m_editElement.addField(field); 153 if (shouldDayOfMonthFieldDisabled()) { 154 field->setValueAsDate(m_dateValue); 155 field->setDisabled(); 156 } 157 return; 158 } 159 160 case DateTimeFormat::FieldTypeHour11: { 161 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12); 162 RefPtr<DateTimeFieldElement> field = DateTimeHour11FieldElement::create(document, m_editElement, m_hour23Range, step); 163 m_editElement.addField(field); 164 if (shouldHourFieldDisabled()) { 165 field->setValueAsDate(m_dateValue); 166 field->setDisabled(); 167 } 168 return; 169 } 170 171 case DateTimeFormat::FieldTypeHour12: { 172 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12); 173 RefPtr<DateTimeFieldElement> field = DateTimeHour12FieldElement::create(document, m_editElement, m_hour23Range, step); 174 m_editElement.addField(field); 175 if (shouldHourFieldDisabled()) { 176 field->setValueAsDate(m_dateValue); 177 field->setDisabled(); 178 } 179 return; 180 } 181 182 case DateTimeFormat::FieldTypeHour23: { 183 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay); 184 RefPtr<DateTimeFieldElement> field = DateTimeHour23FieldElement::create(document, m_editElement, m_hour23Range, step); 185 m_editElement.addField(field); 186 if (shouldHourFieldDisabled()) { 187 field->setValueAsDate(m_dateValue); 188 field->setDisabled(); 189 } 190 return; 191 } 192 193 case DateTimeFormat::FieldTypeHour24: { 194 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay); 195 RefPtr<DateTimeFieldElement> field = DateTimeHour24FieldElement::create(document, m_editElement, m_hour23Range, step); 196 m_editElement.addField(field); 197 if (shouldHourFieldDisabled()) { 198 field->setValueAsDate(m_dateValue); 199 field->setDisabled(); 200 } 201 return; 202 } 203 204 case DateTimeFormat::FieldTypeMinute: { 205 DateTimeNumericFieldElement::Step step = createStep(msPerMinute, msPerHour); 206 RefPtr<DateTimeNumericFieldElement> field = DateTimeMinuteFieldElement::create(document, m_editElement, m_minuteRange, step); 207 m_editElement.addField(field); 208 if (shouldMinuteFieldDisabled()) { 209 field->setValueAsDate(m_dateValue); 210 field->setDisabled(); 211 } 212 return; 213 } 214 215 case DateTimeFormat::FieldTypeMonth: // Fallthrough. 216 case DateTimeFormat::FieldTypeMonthStandAlone: { 217 int minMonth = 0, maxMonth = 11; 218 if (m_parameters.minimum.type() != DateComponents::Invalid 219 && m_parameters.maximum.type() != DateComponents::Invalid 220 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear() 221 && m_parameters.minimum.month() <= m_parameters.maximum.month()) { 222 minMonth = m_parameters.minimum.month(); 223 maxMonth = m_parameters.maximum.month(); 224 } 225 RefPtr<DateTimeFieldElement> field; 226 switch (count) { 227 case countForNarrowMonth: // Fallthrough. 228 case countForAbbreviatedMonth: 229 field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.shortMonthLabels() : m_parameters.locale.shortStandAloneMonthLabels(), minMonth, maxMonth); 230 break; 231 case countForFullMonth: 232 field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.monthLabels() : m_parameters.locale.standAloneMonthLabels(), minMonth, maxMonth); 233 break; 234 default: 235 field = DateTimeMonthFieldElement::create(document, m_editElement, m_parameters.placeholderForMonth, DateTimeNumericFieldElement::Range(minMonth + 1, maxMonth + 1)); 236 break; 237 } 238 m_editElement.addField(field); 239 if (minMonth == maxMonth && minMonth == m_dateValue.month() && m_dateValue.type() != DateComponents::Month) { 240 field->setValueAsDate(m_dateValue); 241 field->setDisabled(); 242 } 243 return; 244 } 245 246 case DateTimeFormat::FieldTypePeriod: { 247 RefPtr<DateTimeFieldElement> field = DateTimeAMPMFieldElement::create(document, m_editElement, m_parameters.locale.timeAMPMLabels()); 248 m_editElement.addField(field); 249 if (shouldAMPMFieldDisabled()) { 250 field->setValueAsDate(m_dateValue); 251 field->setDisabled(); 252 } 253 return; 254 } 255 256 case DateTimeFormat::FieldTypeSecond: { 257 DateTimeNumericFieldElement::Step step = createStep(msPerSecond, msPerMinute); 258 RefPtr<DateTimeNumericFieldElement> field = DateTimeSecondFieldElement::create(document, m_editElement, m_secondRange, step); 259 m_editElement.addField(field); 260 if (shouldSecondFieldDisabled()) { 261 field->setValueAsDate(m_dateValue); 262 field->setDisabled(); 263 } 264 265 if (needMillisecondField()) { 266 visitLiteral(m_parameters.locale.localizedDecimalSeparator()); 267 visitField(DateTimeFormat::FieldTypeFractionalSecond, 3); 268 } 269 return; 270 } 271 272 case DateTimeFormat::FieldTypeFractionalSecond: { 273 DateTimeNumericFieldElement::Step step = createStep(1, msPerSecond); 274 RefPtr<DateTimeNumericFieldElement> field = DateTimeMillisecondFieldElement::create(document, m_editElement, m_millisecondRange, step); 275 m_editElement.addField(field); 276 if (shouldMillisecondFieldDisabled()) { 277 field->setValueAsDate(m_dateValue); 278 field->setDisabled(); 279 } 280 return; 281 } 282 283 case DateTimeFormat::FieldTypeWeekOfYear: { 284 DateTimeNumericFieldElement::Range range(DateComponents::minimumWeekNumber, DateComponents::maximumWeekNumber); 285 if (m_parameters.minimum.type() != DateComponents::Invalid 286 && m_parameters.maximum.type() != DateComponents::Invalid 287 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear() 288 && m_parameters.minimum.week() <= m_parameters.maximum.week()) { 289 range.minimum = m_parameters.minimum.week(); 290 range.maximum = m_parameters.maximum.week(); 291 } 292 m_editElement.addField(DateTimeWeekFieldElement::create(document, m_editElement, range)); 293 return; 294 } 295 296 case DateTimeFormat::FieldTypeYear: { 297 DateTimeYearFieldElement::Parameters yearParams; 298 if (m_parameters.minimum.type() == DateComponents::Invalid) { 299 yearParams.minimumYear = DateComponents::minimumYear(); 300 yearParams.minIsSpecified = false; 301 } else { 302 yearParams.minimumYear = m_parameters.minimum.fullYear(); 303 yearParams.minIsSpecified = true; 304 } 305 if (m_parameters.maximum.type() == DateComponents::Invalid) { 306 yearParams.maximumYear = DateComponents::maximumYear(); 307 yearParams.maxIsSpecified = false; 308 } else { 309 yearParams.maximumYear = m_parameters.maximum.fullYear(); 310 yearParams.maxIsSpecified = true; 311 } 312 if (yearParams.minimumYear > yearParams.maximumYear) { 313 std::swap(yearParams.minimumYear, yearParams.maximumYear); 314 std::swap(yearParams.minIsSpecified, yearParams.maxIsSpecified); 315 } 316 yearParams.placeholder = m_parameters.placeholderForYear; 317 RefPtr<DateTimeFieldElement> field = DateTimeYearFieldElement::create(document, m_editElement, yearParams); 318 m_editElement.addField(field); 319 if (shouldYearFieldDisabled()) { 320 field->setValueAsDate(m_dateValue); 321 field->setDisabled(); 322 } 323 return; 324 } 325 326 default: 327 return; 328 } 329 } 330 331 bool DateTimeEditBuilder::shouldAMPMFieldDisabled() const 332 { 333 return shouldHourFieldDisabled() 334 || (m_hour23Range.minimum < 12 && m_hour23Range.maximum < 12 && m_dateValue.hour() < 12) 335 || (m_hour23Range.minimum >= 12 && m_hour23Range.maximum >= 12 && m_dateValue.hour() >= 12); 336 } 337 338 bool DateTimeEditBuilder::shouldDayOfMonthFieldDisabled() const 339 { 340 return m_dayRange.isSingleton() && m_dayRange.minimum == m_dateValue.monthDay() && m_dateValue.type() != DateComponents::Date; 341 } 342 343 bool DateTimeEditBuilder::shouldHourFieldDisabled() const 344 { 345 if (m_hour23Range.isSingleton() && m_hour23Range.minimum == m_dateValue.hour() 346 && !(shouldMinuteFieldDisabled() && shouldSecondFieldDisabled() && shouldMillisecondFieldDisabled())) 347 return true; 348 349 if (m_dateValue.type() == DateComponents::Time) 350 return false; 351 ASSERT(m_dateValue.type() == DateComponents::DateTimeLocal); 352 353 if (shouldDayOfMonthFieldDisabled()) { 354 ASSERT(m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()); 355 ASSERT(m_parameters.minimum.month() == m_parameters.maximum.month()); 356 return false; 357 } 358 359 const Decimal decimalMsPerDay(static_cast<int>(msPerDay)); 360 Decimal hourPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerDay) / static_cast<int>(msPerHour)).floor(); 361 return hourPartOfMinimum == m_dateValue.hour() && stepRange().step().remainder(decimalMsPerDay).isZero(); 362 } 363 364 bool DateTimeEditBuilder::shouldMillisecondFieldDisabled() const 365 { 366 if (m_millisecondRange.isSingleton() && m_millisecondRange.minimum == m_dateValue.millisecond()) 367 return true; 368 369 const Decimal decimalMsPerSecond(static_cast<int>(msPerSecond)); 370 return stepRange().minimum().abs().remainder(decimalMsPerSecond) == m_dateValue.millisecond() && stepRange().step().remainder(decimalMsPerSecond).isZero(); 371 } 372 373 bool DateTimeEditBuilder::shouldMinuteFieldDisabled() const 374 { 375 if (m_minuteRange.isSingleton() && m_minuteRange.minimum == m_dateValue.minute()) 376 return true; 377 378 const Decimal decimalMsPerHour(static_cast<int>(msPerHour)); 379 Decimal minutePartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerHour) / static_cast<int>(msPerMinute)).floor(); 380 return minutePartOfMinimum == m_dateValue.minute() && stepRange().step().remainder(decimalMsPerHour).isZero(); 381 } 382 383 bool DateTimeEditBuilder::shouldSecondFieldDisabled() const 384 { 385 if (m_secondRange.isSingleton() && m_secondRange.minimum == m_dateValue.second()) 386 return true; 387 388 const Decimal decimalMsPerMinute(static_cast<int>(msPerMinute)); 389 Decimal secondPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerMinute) / static_cast<int>(msPerSecond)).floor(); 390 return secondPartOfMinimum == m_dateValue.second() && stepRange().step().remainder(decimalMsPerMinute).isZero(); 391 } 392 393 bool DateTimeEditBuilder::shouldYearFieldDisabled() const 394 { 395 return m_parameters.minimum.type() != DateComponents::Invalid 396 && m_parameters.maximum.type() != DateComponents::Invalid 397 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear() 398 && m_parameters.minimum.fullYear() == m_dateValue.fullYear(); 399 } 400 401 void DateTimeEditBuilder::visitLiteral(const String& text) 402 { 403 DEFINE_STATIC_LOCAL(AtomicString, textPseudoId, ("-webkit-datetime-edit-text", AtomicString::ConstructFromLiteral)); 404 ASSERT(text.length()); 405 RefPtr<HTMLDivElement> element = HTMLDivElement::create(m_editElement.document()); 406 element->setPart(textPseudoId); 407 if (m_parameters.locale.isRTL() && text.length()) { 408 Direction dir = direction(text[0]); 409 if (dir == SegmentSeparator || dir == WhiteSpaceNeutral || dir == OtherNeutral) 410 element->appendChild(Text::create(m_editElement.document(), String(&rightToLeftMark, 1))); 411 } 412 element->appendChild(Text::create(m_editElement.document(), text)); 413 m_editElement.fieldsWrapperElement()->appendChild(element, ASSERT_NO_EXCEPTION, AttachLazily); 414 } 415 416 DateTimeNumericFieldElement::Step DateTimeEditBuilder::createStep(double msPerFieldUnit, double msPerFieldSize) const 417 { 418 const Decimal msPerFieldUnitDecimal(static_cast<int>(msPerFieldUnit)); 419 const Decimal msPerFieldSizeDecimal(static_cast<int>(msPerFieldSize)); 420 Decimal stepMilliseconds = stepRange().step(); 421 ASSERT(!msPerFieldUnitDecimal.isZero()); 422 ASSERT(!msPerFieldSizeDecimal.isZero()); 423 ASSERT(!stepMilliseconds.isZero()); 424 425 DateTimeNumericFieldElement::Step step(1, 0); 426 427 if (stepMilliseconds.remainder(msPerFieldSizeDecimal).isZero()) 428 stepMilliseconds = msPerFieldSizeDecimal; 429 430 if (msPerFieldSizeDecimal.remainder(stepMilliseconds).isZero() && stepMilliseconds.remainder(msPerFieldUnitDecimal).isZero()) { 431 step.step = static_cast<int>((stepMilliseconds / msPerFieldUnitDecimal).toDouble()); 432 step.stepBase = static_cast<int>((stepRange().stepBase() / msPerFieldUnitDecimal).floor().remainder(msPerFieldSizeDecimal / msPerFieldUnitDecimal).toDouble()); 433 } 434 return step; 435 } 436 437 // ---------------------------- 438 439 DateTimeEditElement::EditControlOwner::~EditControlOwner() 440 { 441 } 442 443 DateTimeEditElement::DateTimeEditElement(Document* document, EditControlOwner& editControlOwner) 444 : HTMLDivElement(divTag, document) 445 , m_editControlOwner(&editControlOwner) 446 { 447 setHasCustomStyleCallbacks(); 448 } 449 450 DateTimeEditElement::~DateTimeEditElement() 451 { 452 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 453 m_fields[fieldIndex]->removeEventHandler(); 454 } 455 456 inline Element* DateTimeEditElement::fieldsWrapperElement() const 457 { 458 ASSERT(firstChild()); 459 return toElement(firstChild()); 460 } 461 462 void DateTimeEditElement::addField(PassRefPtr<DateTimeFieldElement> field) 463 { 464 if (m_fields.size() == m_fields.capacity()) 465 return; 466 m_fields.append(field.get()); 467 fieldsWrapperElement()->appendChild(field, ASSERT_NO_EXCEPTION, AttachLazily); 468 } 469 470 bool DateTimeEditElement::anyEditableFieldsHaveValues() const 471 { 472 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { 473 if (!m_fields[fieldIndex]->isDisabled() && m_fields[fieldIndex]->hasValue()) 474 return true; 475 } 476 return false; 477 } 478 479 void DateTimeEditElement::blurByOwner() 480 { 481 if (DateTimeFieldElement* field = focusedField()) 482 field->blur(); 483 } 484 485 PassRefPtr<DateTimeEditElement> DateTimeEditElement::create(Document* document, EditControlOwner& editControlOwner) 486 { 487 RefPtr<DateTimeEditElement> container = adoptRef(new DateTimeEditElement(document, editControlOwner)); 488 container->setPart(AtomicString("-webkit-datetime-edit", AtomicString::ConstructFromLiteral)); 489 container->setAttribute(idAttr, ShadowElementNames::dateTimeEdit()); 490 return container.release(); 491 } 492 493 PassRefPtr<RenderStyle> DateTimeEditElement::customStyleForRenderer() 494 { 495 // FIXME: This is a kind of layout. We might want to introduce new renderer. 496 FontCachePurgePreventer fontCachePurgePreventer; 497 RefPtr<RenderStyle> originalStyle = originalStyleForRenderer(); 498 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get()); 499 float width = 0; 500 for (Node* child = fieldsWrapperElement()->firstChild(); child; child = child->nextSibling()) { 501 if (!child->isElementNode()) 502 continue; 503 Element* childElement = toElement(child); 504 if (childElement->isDateTimeFieldElement()) { 505 // We need to pass the Font of this element because child elements 506 // can't resolve inherited style at this timing. 507 width += static_cast<DateTimeFieldElement*>(childElement)->maximumWidth(style->font()); 508 } else { 509 // ::-webkit-datetime-edit-text case. It has no 510 // border/padding/margin in html.css. 511 width += style->font().width(childElement->textContent()); 512 } 513 } 514 style->setWidth(Length(ceilf(width), Fixed)); 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->setPart(fieldsWrapperPseudoId); 656 appendChild(element.get(), ASSERT_NO_EXCEPTION, AttachLazily); 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