| /* |
| * Copyright (C) 2012 Google 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" |
| #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) |
| #include "core/html/shadow/DateTimeFieldElement.h" |
| |
| #include "HTMLNames.h" |
| #include "core/dom/KeyboardEvent.h" |
| #include "core/dom/Text.h" |
| #include "core/platform/LocalizedStrings.h" |
| #include "core/platform/text/PlatformLocale.h" |
| #include "wtf/text/WTFString.h" |
| |
| namespace WebCore { |
| |
| using namespace HTMLNames; |
| |
| DateTimeFieldElement::FieldOwner::~FieldOwner() |
| { |
| } |
| |
| DateTimeFieldElement::DateTimeFieldElement(Document& document, FieldOwner& fieldOwner) |
| : HTMLSpanElement(spanTag, document) |
| , m_fieldOwner(&fieldOwner) |
| { |
| } |
| |
| void DateTimeFieldElement::defaultEventHandler(Event* event) |
| { |
| if (event->type() == eventNames().blurEvent) |
| didBlur(); |
| |
| if (event->type() == eventNames().focusEvent) |
| didFocus(); |
| |
| if (event->isKeyboardEvent()) { |
| KeyboardEvent* keyboardEvent = toKeyboardEvent(event); |
| if (!isDisabled() && !isFieldOwnerDisabled() && !isFieldOwnerReadOnly()) { |
| handleKeyboardEvent(keyboardEvent); |
| if (keyboardEvent->defaultHandled()) |
| return; |
| } |
| defaultKeyboardEventHandler(keyboardEvent); |
| if (keyboardEvent->defaultHandled()) |
| return; |
| } |
| |
| HTMLElement::defaultEventHandler(event); |
| } |
| |
| void DateTimeFieldElement::defaultKeyboardEventHandler(KeyboardEvent* keyboardEvent) |
| { |
| if (keyboardEvent->type() != eventNames().keydownEvent) |
| return; |
| |
| if (isDisabled() || isFieldOwnerDisabled()) |
| return; |
| |
| const String& keyIdentifier = keyboardEvent->keyIdentifier(); |
| |
| if (keyIdentifier == "Left") { |
| if (!m_fieldOwner) |
| return; |
| // FIXME: We'd like to use FocusController::advanceFocus(FocusDirectionLeft, ...) |
| // but it doesn't work for shadow nodes. webkit.org/b/104650 |
| if (!localeForOwner().isRTL() && m_fieldOwner->focusOnPreviousField(*this)) |
| keyboardEvent->setDefaultHandled(); |
| return; |
| } |
| |
| if (keyIdentifier == "Right") { |
| if (!m_fieldOwner) |
| return; |
| // FIXME: We'd like to use FocusController::advanceFocus(FocusDirectionRight, ...) |
| // but it doesn't work for shadow nodes. webkit.org/b/104650 |
| if (!localeForOwner().isRTL() && m_fieldOwner->focusOnNextField(*this)) |
| keyboardEvent->setDefaultHandled(); |
| return; |
| } |
| |
| if (isFieldOwnerReadOnly()) |
| return; |
| |
| if (keyIdentifier == "Down") { |
| if (keyboardEvent->getModifierState("Alt")) |
| return; |
| keyboardEvent->setDefaultHandled(); |
| stepDown(); |
| return; |
| } |
| |
| if (keyIdentifier == "Up") { |
| keyboardEvent->setDefaultHandled(); |
| stepUp(); |
| return; |
| } |
| |
| if (keyIdentifier == "U+0008" || keyIdentifier == "U+007F") { |
| keyboardEvent->setDefaultHandled(); |
| setEmptyValue(DispatchEvent); |
| return; |
| } |
| } |
| |
| void DateTimeFieldElement::didBlur() |
| { |
| if (m_fieldOwner) |
| m_fieldOwner->didBlurFromField(); |
| } |
| |
| void DateTimeFieldElement::didFocus() |
| { |
| if (m_fieldOwner) |
| m_fieldOwner->didFocusOnField(); |
| } |
| |
| void DateTimeFieldElement::focusOnNextField() |
| { |
| if (!m_fieldOwner) |
| return; |
| m_fieldOwner->focusOnNextField(*this); |
| } |
| |
| void DateTimeFieldElement::initialize(const AtomicString& pseudo, const String& axHelpText, int axMinimum, int axMaximum) |
| { |
| // On accessibility, DateTimeFieldElement acts like spin button. |
| setAttribute(roleAttr, AtomicString("spinbutton", AtomicString::ConstructFromLiteral)); |
| setAttribute(aria_valuetextAttr, AXDateTimeFieldEmptyValueText()); |
| setAttribute(aria_valueminAttr, String::number(axMinimum)); |
| setAttribute(aria_valuemaxAttr, String::number(axMaximum)); |
| |
| setAttribute(aria_helpAttr, axHelpText); |
| setPart(pseudo); |
| appendChild(Text::create(document(), visibleValue())); |
| } |
| |
| bool DateTimeFieldElement::isDateTimeFieldElement() const |
| { |
| return true; |
| } |
| |
| bool DateTimeFieldElement::isFieldOwnerDisabled() const |
| { |
| return m_fieldOwner && m_fieldOwner->isFieldOwnerDisabled(); |
| } |
| |
| bool DateTimeFieldElement::isFieldOwnerReadOnly() const |
| { |
| return m_fieldOwner && m_fieldOwner->isFieldOwnerReadOnly(); |
| } |
| |
| bool DateTimeFieldElement::isDisabled() const |
| { |
| return fastHasAttribute(disabledAttr); |
| } |
| |
| Locale& DateTimeFieldElement::localeForOwner() const |
| { |
| return document().getCachedLocale(localeIdentifier()); |
| } |
| |
| AtomicString DateTimeFieldElement::localeIdentifier() const |
| { |
| return m_fieldOwner ? m_fieldOwner->localeIdentifier() : nullAtom; |
| } |
| |
| float DateTimeFieldElement::maximumWidth(const Font&) |
| { |
| const float paddingLeftAndRight = 2; // This should match to html.css. |
| return paddingLeftAndRight; |
| } |
| |
| void DateTimeFieldElement::setDisabled() |
| { |
| // Set HTML attribute disabled to change apperance. |
| setBooleanAttribute(disabledAttr, true); |
| setNeedsStyleRecalc(); |
| } |
| |
| bool DateTimeFieldElement::supportsFocus() const |
| { |
| return !isDisabled() && !isFieldOwnerDisabled(); |
| } |
| |
| void DateTimeFieldElement::updateVisibleValue(EventBehavior eventBehavior) |
| { |
| Text* const textNode = toText(firstChild()); |
| const String newVisibleValue = visibleValue(); |
| ASSERT(newVisibleValue.length() > 0); |
| |
| if (textNode->wholeText() == newVisibleValue) |
| return; |
| |
| textNode->replaceWholeText(newVisibleValue); |
| if (hasValue()) { |
| setAttribute(aria_valuetextAttr, newVisibleValue); |
| setAttribute(aria_valuenowAttr, String::number(valueForARIAValueNow())); |
| } else { |
| setAttribute(aria_valuetextAttr, AXDateTimeFieldEmptyValueText()); |
| removeAttribute(aria_valuenowAttr); |
| } |
| |
| if (eventBehavior == DispatchEvent && m_fieldOwner) |
| m_fieldOwner->fieldValueChanged(); |
| } |
| |
| int DateTimeFieldElement::valueForARIAValueNow() const |
| { |
| return valueAsInteger(); |
| } |
| |
| } // namespace WebCore |
| |
| #endif |