| /* |
| * Copyright (C) 2012 Google Inc. All rights reserved. |
| * Copyright (C) 2020 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "DateTimeFieldElement.h" |
| |
| #if ENABLE(DATE_AND_TIME_INPUT_TYPES) |
| |
| #include "CSSPropertyNames.h" |
| #include "DateComponents.h" |
| #include "EventNames.h" |
| #include "HTMLNames.h" |
| #include "KeyboardEvent.h" |
| #include "LocalizedStrings.h" |
| #include "PlatformLocale.h" |
| #include "RenderStyle.h" |
| #include "RenderTheme.h" |
| #include "StyleResolver.h" |
| #include "Text.h" |
| #include <wtf/IsoMallocInlines.h> |
| #include <wtf/text/WTFString.h> |
| |
| namespace WebCore { |
| |
| using namespace HTMLNames; |
| |
| WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeFieldElement); |
| |
| DateTimeFieldElement::FieldOwner::~FieldOwner() = default; |
| |
| DateTimeFieldElement::DateTimeFieldElement(Document& document, FieldOwner& fieldOwner) |
| : HTMLDivElement(divTag, document) |
| , m_fieldOwner(fieldOwner) |
| { |
| setHasCustomStyleResolveCallbacks(); |
| } |
| |
| void DateTimeFieldElement::initialize(const AtomString& pseudo) |
| { |
| setPseudo(pseudo); |
| } |
| |
| std::optional<Style::ElementStyle> DateTimeFieldElement::resolveCustomStyle(const Style::ResolutionContext& resolutionContext, const RenderStyle* shadowHostStyle) |
| { |
| auto elementStyle = resolveStyle(resolutionContext); |
| if (!elementStyle.renderStyle) |
| return std::nullopt; |
| |
| auto& style = *elementStyle.renderStyle; |
| adjustMinWidth(style); |
| |
| if (!hasValue() && shadowHostStyle) { |
| auto textColor = shadowHostStyle->visitedDependentColorWithColorFilter(CSSPropertyColor); |
| auto backgroundColor = shadowHostStyle->visitedDependentColorWithColorFilter(CSSPropertyBackgroundColor); |
| style.setColor(RenderTheme::singleton().datePlaceholderTextColor(textColor, backgroundColor)); |
| } |
| |
| return elementStyle; |
| } |
| |
| void DateTimeFieldElement::defaultEventHandler(Event& event) |
| { |
| if (event.type() == eventNames().blurEvent) |
| handleBlurEvent(event); |
| |
| if (is<KeyboardEvent>(event)) { |
| auto& keyboardEvent = downcast<KeyboardEvent>(event); |
| if (!isFieldOwnerDisabled() && !isFieldOwnerReadOnly()) { |
| handleKeyboardEvent(keyboardEvent); |
| if (keyboardEvent.defaultHandled()) |
| return; |
| } |
| |
| defaultKeyboardEventHandler(keyboardEvent); |
| if (keyboardEvent.defaultHandled()) |
| return; |
| } |
| |
| HTMLDivElement::defaultEventHandler(event); |
| } |
| |
| void DateTimeFieldElement::defaultKeyboardEventHandler(KeyboardEvent& keyboardEvent) |
| { |
| if (isFieldOwnerDisabled()) |
| return; |
| |
| if (keyboardEvent.type() != eventNames().keydownEvent) |
| return; |
| |
| auto key = keyboardEvent.keyIdentifier(); |
| auto code = keyboardEvent.code(); |
| |
| if (key == "Left" && m_fieldOwner && m_fieldOwner->focusOnPreviousField(*this)) { |
| keyboardEvent.setDefaultHandled(); |
| return; |
| } |
| |
| if ((key == "Right" || code == "Comma" || code == "Minus" || code == "Period" || code == "Slash" || code == "Semicolon") |
| && m_fieldOwner && m_fieldOwner->focusOnNextField(*this)) { |
| keyboardEvent.setDefaultHandled(); |
| return; |
| } |
| |
| if (isFieldOwnerReadOnly()) |
| return; |
| |
| if (key == "Up") { |
| stepUp(); |
| keyboardEvent.setDefaultHandled(); |
| return; |
| } |
| |
| if (key == "Down") { |
| stepDown(); |
| keyboardEvent.setDefaultHandled(); |
| return; |
| } |
| |
| // Clear value when pressing backspace or delete. |
| if (key == "U+0008" || key == "U+007F") { |
| setEmptyValue(DispatchInputAndChangeEvents); |
| keyboardEvent.setDefaultHandled(); |
| return; |
| } |
| } |
| |
| bool DateTimeFieldElement::isFieldOwnerDisabled() const |
| { |
| return m_fieldOwner && m_fieldOwner->isFieldOwnerDisabled(); |
| } |
| |
| bool DateTimeFieldElement::isFieldOwnerReadOnly() const |
| { |
| return m_fieldOwner && m_fieldOwner->isFieldOwnerReadOnly(); |
| } |
| |
| bool DateTimeFieldElement::isFocusable() const |
| { |
| if (isFieldOwnerDisabled()) |
| return false; |
| return HTMLElement::isFocusable(); |
| } |
| |
| void DateTimeFieldElement::handleBlurEvent(Event& event) |
| { |
| if (m_fieldOwner) |
| m_fieldOwner->didBlurFromField(event); |
| } |
| |
| Locale& DateTimeFieldElement::localeForOwner() const |
| { |
| return document().getCachedLocale(localeIdentifier()); |
| } |
| |
| AtomString DateTimeFieldElement::localeIdentifier() const |
| { |
| return m_fieldOwner ? m_fieldOwner->localeIdentifier() : nullAtom(); |
| } |
| |
| String DateTimeFieldElement::visibleValue() const |
| { |
| return hasValue() ? value() : placeholderValue(); |
| } |
| |
| void DateTimeFieldElement::updateVisibleValue(EventBehavior eventBehavior) |
| { |
| if (!firstChild()) |
| appendChild(Text::create(document(), emptyString())); |
| |
| auto& textNode = downcast<Text>(*firstChild()); |
| String newVisibleValue = visibleValue(); |
| if (textNode.wholeText() != newVisibleValue) |
| textNode.replaceWholeText(newVisibleValue); |
| |
| if (eventBehavior == DispatchInputAndChangeEvents && m_fieldOwner) |
| m_fieldOwner->fieldValueChanged(); |
| } |
| |
| bool DateTimeFieldElement::supportsFocus() const |
| { |
| return true; |
| } |
| |
| } // namespace WebCore |
| |
| #endif // ENABLE(DATE_AND_TIME_INPUT_TYPES) |