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 "bindings/core/v8/ExceptionStatePlaceholder.h" 31 #include "core/HTMLNames.h" 32 #include "core/dom/Document.h" 33 #include "core/dom/Text.h" 34 #include "core/events/MouseEvent.h" 35 #include "core/html/forms/DateTimeFieldsState.h" 36 #include "core/html/shadow/DateTimeFieldElements.h" 37 #include "core/html/shadow/ShadowElementNames.h" 38 #include "core/rendering/style/RenderStyle.h" 39 #include "core/rendering/style/StyleInheritedData.h" 40 #include "platform/fonts/FontCache.h" 41 #include "platform/text/DateTimeFormat.h" 42 #include "platform/text/PlatformLocale.h" 43 #include "wtf/DateMath.h" 44 45 namespace blink { 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& document = m_editElement.document(); 148 149 switch (fieldType) { 150 case DateTimeFormat::FieldTypeDayOfMonth: { 151 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<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 RefPtrWillBeRawPtr<HTMLDivElement> element = HTMLDivElement::create(m_editElement.document()); 406 element->setShadowPseudoId(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); 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(document) 445 , m_editControlOwner(&editControlOwner) 446 { 447 setHasCustomStyleCallbacks(); 448 } 449 450 DateTimeEditElement::~DateTimeEditElement() 451 { 452 #if !ENABLE(OILPAN) 453 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 454 m_fields[fieldIndex]->removeEventHandler(); 455 #endif 456 } 457 458 void DateTimeEditElement::trace(Visitor* visitor) 459 { 460 #if ENABLE(OILPAN) 461 visitor->trace(m_fields); 462 #endif 463 visitor->trace(m_editControlOwner); 464 HTMLDivElement::trace(visitor); 465 } 466 467 inline Element* DateTimeEditElement::fieldsWrapperElement() const 468 { 469 ASSERT(firstChild()); 470 return toElement(firstChild()); 471 } 472 473 void DateTimeEditElement::addField(PassRefPtrWillBeRawPtr<DateTimeFieldElement> field) 474 { 475 if (m_fields.size() == m_fields.capacity()) 476 return; 477 m_fields.append(field.get()); 478 fieldsWrapperElement()->appendChild(field); 479 } 480 481 bool DateTimeEditElement::anyEditableFieldsHaveValues() const 482 { 483 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { 484 if (!m_fields[fieldIndex]->isDisabled() && m_fields[fieldIndex]->hasValue()) 485 return true; 486 } 487 return false; 488 } 489 490 void DateTimeEditElement::blurByOwner() 491 { 492 if (DateTimeFieldElement* field = focusedField()) 493 field->blur(); 494 } 495 496 PassRefPtrWillBeRawPtr<DateTimeEditElement> DateTimeEditElement::create(Document& document, EditControlOwner& editControlOwner) 497 { 498 RefPtrWillBeRawPtr<DateTimeEditElement> container = adoptRefWillBeNoop(new DateTimeEditElement(document, editControlOwner)); 499 container->setShadowPseudoId(AtomicString("-webkit-datetime-edit", AtomicString::ConstructFromLiteral)); 500 container->setAttribute(idAttr, ShadowElementNames::dateTimeEdit()); 501 return container.release(); 502 } 503 504 PassRefPtr<RenderStyle> DateTimeEditElement::customStyleForRenderer() 505 { 506 // FIXME: This is a kind of layout. We might want to introduce new renderer. 507 FontCachePurgePreventer fontCachePurgePreventer; 508 RefPtr<RenderStyle> originalStyle = originalStyleForRenderer(); 509 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get()); 510 float width = 0; 511 for (Node* child = fieldsWrapperElement()->firstChild(); child; child = child->nextSibling()) { 512 if (!child->isElementNode()) 513 continue; 514 Element* childElement = toElement(child); 515 if (childElement->isDateTimeFieldElement()) { 516 // We need to pass the Font of this element because child elements 517 // can't resolve inherited style at this timing. 518 width += static_cast<DateTimeFieldElement*>(childElement)->maximumWidth(style->font()); 519 } else { 520 // ::-webkit-datetime-edit-text case. It has no 521 // border/padding/margin in html.css. 522 width += style->font().width(childElement->textContent()); 523 } 524 } 525 style->setWidth(Length(ceilf(width), Fixed)); 526 style->setUnique(); 527 return style.release(); 528 } 529 530 void DateTimeEditElement::didBlurFromField() 531 { 532 if (m_editControlOwner) 533 m_editControlOwner->didBlurFromControl(); 534 } 535 536 void DateTimeEditElement::didFocusOnField() 537 { 538 if (m_editControlOwner) 539 m_editControlOwner->didFocusOnControl(); 540 } 541 542 void DateTimeEditElement::disabledStateChanged() 543 { 544 updateUIState(); 545 } 546 547 DateTimeFieldElement* DateTimeEditElement::fieldAt(size_t fieldIndex) const 548 { 549 return fieldIndex < m_fields.size() ? m_fields[fieldIndex].get() : 0; 550 } 551 552 size_t DateTimeEditElement::fieldIndexOf(const DateTimeFieldElement& field) const 553 { 554 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { 555 if (m_fields[fieldIndex] == &field) 556 return fieldIndex; 557 } 558 return invalidFieldIndex; 559 } 560 561 void DateTimeEditElement::focusIfNoFocus() 562 { 563 if (focusedFieldIndex() != invalidFieldIndex) 564 return; 565 focusOnNextFocusableField(0); 566 } 567 568 void DateTimeEditElement::focusByOwner(Element* oldFocusedElement) 569 { 570 if (oldFocusedElement && oldFocusedElement->isDateTimeFieldElement()) { 571 DateTimeFieldElement* oldFocusedField = static_cast<DateTimeFieldElement*>(oldFocusedElement); 572 size_t index = fieldIndexOf(*oldFocusedField); 573 if (index != invalidFieldIndex && oldFocusedField->isFocusable()) { 574 oldFocusedField->focus(); 575 return; 576 } 577 } 578 focusOnNextFocusableField(0); 579 } 580 581 DateTimeFieldElement* DateTimeEditElement::focusedField() const 582 { 583 return fieldAt(focusedFieldIndex()); 584 } 585 586 size_t DateTimeEditElement::focusedFieldIndex() const 587 { 588 Element* const focusedFieldElement = document().focusedElement(); 589 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { 590 if (m_fields[fieldIndex] == focusedFieldElement) 591 return fieldIndex; 592 } 593 return invalidFieldIndex; 594 } 595 596 void DateTimeEditElement::fieldValueChanged() 597 { 598 if (m_editControlOwner) 599 m_editControlOwner->editControlValueChanged(); 600 } 601 602 bool DateTimeEditElement::focusOnNextFocusableField(size_t startIndex) 603 { 604 for (size_t fieldIndex = startIndex; fieldIndex < m_fields.size(); ++fieldIndex) { 605 if (m_fields[fieldIndex]->isFocusable()) { 606 m_fields[fieldIndex]->focus(); 607 return true; 608 } 609 } 610 return false; 611 } 612 613 bool DateTimeEditElement::focusOnNextField(const DateTimeFieldElement& field) 614 { 615 const size_t startFieldIndex = fieldIndexOf(field); 616 if (startFieldIndex == invalidFieldIndex) 617 return false; 618 return focusOnNextFocusableField(startFieldIndex + 1); 619 } 620 621 bool DateTimeEditElement::focusOnPreviousField(const DateTimeFieldElement& field) 622 { 623 const size_t startFieldIndex = fieldIndexOf(field); 624 if (startFieldIndex == invalidFieldIndex) 625 return false; 626 size_t fieldIndex = startFieldIndex; 627 while (fieldIndex > 0) { 628 --fieldIndex; 629 if (m_fields[fieldIndex]->isFocusable()) { 630 m_fields[fieldIndex]->focus(); 631 return true; 632 } 633 } 634 return false; 635 } 636 637 bool DateTimeEditElement::isDateTimeEditElement() const 638 { 639 return true; 640 } 641 642 bool DateTimeEditElement::isDisabled() const 643 { 644 return m_editControlOwner && m_editControlOwner->isEditControlOwnerDisabled(); 645 } 646 647 bool DateTimeEditElement::isFieldOwnerDisabled() const 648 { 649 return isDisabled(); 650 } 651 652 bool DateTimeEditElement::isFieldOwnerReadOnly() const 653 { 654 return isReadOnly(); 655 } 656 657 bool DateTimeEditElement::isReadOnly() const 658 { 659 return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly(); 660 } 661 662 void DateTimeEditElement::layout(const LayoutParameters& layoutParameters, const DateComponents& dateValue) 663 { 664 DEFINE_STATIC_LOCAL(AtomicString, fieldsWrapperPseudoId, ("-webkit-datetime-edit-fields-wrapper", AtomicString::ConstructFromLiteral)); 665 if (!hasChildren()) { 666 RefPtrWillBeRawPtr<HTMLDivElement> element = HTMLDivElement::create(document()); 667 element->setShadowPseudoId(fieldsWrapperPseudoId); 668 appendChild(element.get()); 669 } 670 Element* fieldsWrapper = fieldsWrapperElement(); 671 672 size_t focusedFieldIndex = this->focusedFieldIndex(); 673 DateTimeFieldElement* const focusedField = fieldAt(focusedFieldIndex); 674 const AtomicString focusedFieldId = focusedField ? focusedField->shadowPseudoId() : nullAtom; 675 676 DateTimeEditBuilder builder(*this, layoutParameters, dateValue); 677 Node* lastChildToBeRemoved = fieldsWrapper->lastChild(); 678 if (!builder.build(layoutParameters.dateTimeFormat) || m_fields.isEmpty()) { 679 lastChildToBeRemoved = fieldsWrapper->lastChild(); 680 builder.build(layoutParameters.fallbackDateTimeFormat); 681 } 682 683 if (focusedFieldIndex != invalidFieldIndex) { 684 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { 685 if (m_fields[fieldIndex]->shadowPseudoId() == focusedFieldId) { 686 focusedFieldIndex = fieldIndex; 687 break; 688 } 689 } 690 if (DateTimeFieldElement* field = fieldAt(std::min(focusedFieldIndex, m_fields.size() - 1))) 691 field->focus(); 692 } 693 694 if (lastChildToBeRemoved) { 695 for (Node* childNode = fieldsWrapper->firstChild(); childNode; childNode = fieldsWrapper->firstChild()) { 696 fieldsWrapper->removeChild(childNode); 697 if (childNode == lastChildToBeRemoved) 698 break; 699 } 700 setNeedsStyleRecalc(SubtreeStyleChange); 701 } 702 } 703 704 AtomicString DateTimeEditElement::localeIdentifier() const 705 { 706 return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom; 707 } 708 709 void DateTimeEditElement::fieldDidChangeValueByKeyboard() 710 { 711 if (m_editControlOwner) 712 m_editControlOwner->editControlDidChangeValueByKeyboard(); 713 } 714 715 void DateTimeEditElement::readOnlyStateChanged() 716 { 717 updateUIState(); 718 } 719 720 void DateTimeEditElement::resetFields() 721 { 722 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 723 m_fields[fieldIndex]->removeEventHandler(); 724 m_fields.shrink(0); 725 } 726 727 void DateTimeEditElement::defaultEventHandler(Event* event) 728 { 729 // In case of control owner forward event to control, e.g. DOM 730 // dispatchEvent method. 731 if (DateTimeFieldElement* field = focusedField()) { 732 field->defaultEventHandler(event); 733 if (event->defaultHandled()) 734 return; 735 } 736 737 HTMLDivElement::defaultEventHandler(event); 738 } 739 740 void DateTimeEditElement::setValueAsDate(const LayoutParameters& layoutParameters, const DateComponents& date) 741 { 742 layout(layoutParameters, date); 743 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 744 m_fields[fieldIndex]->setValueAsDate(date); 745 } 746 747 void DateTimeEditElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) 748 { 749 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 750 m_fields[fieldIndex]->setValueAsDateTimeFieldsState(dateTimeFieldsState); 751 } 752 753 void DateTimeEditElement::setEmptyValue(const LayoutParameters& layoutParameters, const DateComponents& dateForReadOnlyField) 754 { 755 layout(layoutParameters, dateForReadOnlyField); 756 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 757 m_fields[fieldIndex]->setEmptyValue(DateTimeFieldElement::DispatchNoEvent); 758 } 759 760 bool DateTimeEditElement::hasFocusedField() 761 { 762 return focusedFieldIndex() != invalidFieldIndex; 763 } 764 765 void DateTimeEditElement::setOnlyYearMonthDay(const DateComponents& date) 766 { 767 ASSERT(date.type() == DateComponents::Date); 768 769 if (!m_editControlOwner) 770 return; 771 772 DateTimeFieldsState dateTimeFieldsState = valueAsDateTimeFieldsState(); 773 dateTimeFieldsState.setYear(date.fullYear()); 774 dateTimeFieldsState.setMonth(date.month() + 1); 775 dateTimeFieldsState.setDayOfMonth(date.monthDay()); 776 setValueAsDateTimeFieldsState(dateTimeFieldsState); 777 m_editControlOwner->editControlValueChanged(); 778 } 779 780 void DateTimeEditElement::stepDown() 781 { 782 if (DateTimeFieldElement* const field = focusedField()) 783 field->stepDown(); 784 } 785 786 void DateTimeEditElement::stepUp() 787 { 788 if (DateTimeFieldElement* const field = focusedField()) 789 field->stepUp(); 790 } 791 792 void DateTimeEditElement::updateUIState() 793 { 794 if (isDisabled()) { 795 if (DateTimeFieldElement* field = focusedField()) 796 field->blur(); 797 } 798 } 799 800 String DateTimeEditElement::value() const 801 { 802 if (!m_editControlOwner) 803 return emptyString(); 804 return m_editControlOwner->formatDateTimeFieldsState(valueAsDateTimeFieldsState()); 805 } 806 807 DateTimeFieldsState DateTimeEditElement::valueAsDateTimeFieldsState() const 808 { 809 DateTimeFieldsState dateTimeFieldsState; 810 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) 811 m_fields[fieldIndex]->populateDateTimeFieldsState(dateTimeFieldsState); 812 return dateTimeFieldsState; 813 } 814 815 } // namespace blink 816 817 #endif 818