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/DateTimeFieldElement.h" 29 30 #include "HTMLNames.h" 31 #include "core/dom/KeyboardEvent.h" 32 #include "core/dom/Text.h" 33 #include "core/platform/LocalizedStrings.h" 34 #include "core/platform/text/PlatformLocale.h" 35 #include "wtf/text/WTFString.h" 36 37 namespace WebCore { 38 39 using namespace HTMLNames; 40 41 DateTimeFieldElement::FieldOwner::~FieldOwner() 42 { 43 } 44 45 DateTimeFieldElement::DateTimeFieldElement(Document* document, FieldOwner& fieldOwner) 46 : HTMLSpanElement(spanTag, document) 47 , m_fieldOwner(&fieldOwner) 48 { 49 } 50 51 void DateTimeFieldElement::defaultEventHandler(Event* event) 52 { 53 if (event->type() == eventNames().blurEvent) 54 didBlur(); 55 56 if (event->type() == eventNames().focusEvent) 57 didFocus(); 58 59 if (event->isKeyboardEvent()) { 60 KeyboardEvent* keyboardEvent = toKeyboardEvent(event); 61 if (!isDisabled() && !isFieldOwnerDisabled() && !isFieldOwnerReadOnly()) { 62 handleKeyboardEvent(keyboardEvent); 63 if (keyboardEvent->defaultHandled()) 64 return; 65 } 66 defaultKeyboardEventHandler(keyboardEvent); 67 if (keyboardEvent->defaultHandled()) 68 return; 69 } 70 71 HTMLElement::defaultEventHandler(event); 72 } 73 74 void DateTimeFieldElement::defaultKeyboardEventHandler(KeyboardEvent* keyboardEvent) 75 { 76 if (keyboardEvent->type() != eventNames().keydownEvent) 77 return; 78 79 if (isDisabled() || isFieldOwnerDisabled()) 80 return; 81 82 const String& keyIdentifier = keyboardEvent->keyIdentifier(); 83 84 if (keyIdentifier == "Left") { 85 if (!m_fieldOwner) 86 return; 87 // FIXME: We'd like to use FocusController::advanceFocus(FocusDirectionLeft, ...) 88 // but it doesn't work for shadow nodes. webkit.org/b/104650 89 if (!localeForOwner().isRTL() && m_fieldOwner->focusOnPreviousField(*this)) 90 keyboardEvent->setDefaultHandled(); 91 return; 92 } 93 94 if (keyIdentifier == "Right") { 95 if (!m_fieldOwner) 96 return; 97 // FIXME: We'd like to use FocusController::advanceFocus(FocusDirectionRight, ...) 98 // but it doesn't work for shadow nodes. webkit.org/b/104650 99 if (!localeForOwner().isRTL() && m_fieldOwner->focusOnNextField(*this)) 100 keyboardEvent->setDefaultHandled(); 101 return; 102 } 103 104 if (isFieldOwnerReadOnly()) 105 return; 106 107 if (keyIdentifier == "Down") { 108 if (keyboardEvent->getModifierState("Alt")) 109 return; 110 keyboardEvent->setDefaultHandled(); 111 stepDown(); 112 return; 113 } 114 115 if (keyIdentifier == "Up") { 116 keyboardEvent->setDefaultHandled(); 117 stepUp(); 118 return; 119 } 120 121 if (keyIdentifier == "U+0008" || keyIdentifier == "U+007F") { 122 keyboardEvent->setDefaultHandled(); 123 setEmptyValue(DispatchEvent); 124 return; 125 } 126 } 127 128 void DateTimeFieldElement::didBlur() 129 { 130 if (m_fieldOwner) 131 m_fieldOwner->didBlurFromField(); 132 } 133 134 void DateTimeFieldElement::didFocus() 135 { 136 if (m_fieldOwner) 137 m_fieldOwner->didFocusOnField(); 138 } 139 140 void DateTimeFieldElement::focusOnNextField() 141 { 142 if (!m_fieldOwner) 143 return; 144 m_fieldOwner->focusOnNextField(*this); 145 } 146 147 void DateTimeFieldElement::initialize(const AtomicString& pseudo, const String& axHelpText, int axMinimum, int axMaximum) 148 { 149 // On accessibility, DateTimeFieldElement acts like spin button. 150 setAttribute(roleAttr, AtomicString("spinbutton", AtomicString::ConstructFromLiteral)); 151 setAttribute(aria_valuetextAttr, AXDateTimeFieldEmptyValueText()); 152 setAttribute(aria_valueminAttr, String::number(axMinimum)); 153 setAttribute(aria_valuemaxAttr, String::number(axMaximum)); 154 155 setAttribute(aria_helpAttr, axHelpText); 156 setPart(pseudo); 157 appendChild(Text::create(document(), visibleValue())); 158 } 159 160 bool DateTimeFieldElement::isDateTimeFieldElement() const 161 { 162 return true; 163 } 164 165 bool DateTimeFieldElement::isFieldOwnerDisabled() const 166 { 167 return m_fieldOwner && m_fieldOwner->isFieldOwnerDisabled(); 168 } 169 170 bool DateTimeFieldElement::isFieldOwnerReadOnly() const 171 { 172 return m_fieldOwner && m_fieldOwner->isFieldOwnerReadOnly(); 173 } 174 175 bool DateTimeFieldElement::isDisabled() const 176 { 177 return fastHasAttribute(disabledAttr); 178 } 179 180 Locale& DateTimeFieldElement::localeForOwner() const 181 { 182 return document()->getCachedLocale(localeIdentifier()); 183 } 184 185 AtomicString DateTimeFieldElement::localeIdentifier() const 186 { 187 return m_fieldOwner ? m_fieldOwner->localeIdentifier() : nullAtom; 188 } 189 190 float DateTimeFieldElement::maximumWidth(const Font&) 191 { 192 const float paddingLeftAndRight = 2; // This should match to html.css. 193 return paddingLeftAndRight; 194 } 195 196 void DateTimeFieldElement::setDisabled() 197 { 198 // Set HTML attribute disabled to change apperance. 199 setBooleanAttribute(disabledAttr, true); 200 setNeedsStyleRecalc(); 201 } 202 203 bool DateTimeFieldElement::supportsFocus() const 204 { 205 return !isDisabled() && !isFieldOwnerDisabled(); 206 } 207 208 void DateTimeFieldElement::updateVisibleValue(EventBehavior eventBehavior) 209 { 210 Text* const textNode = toText(firstChild()); 211 const String newVisibleValue = visibleValue(); 212 ASSERT(newVisibleValue.length() > 0); 213 214 if (textNode->wholeText() == newVisibleValue) 215 return; 216 217 textNode->replaceWholeText(newVisibleValue); 218 if (hasValue()) { 219 setAttribute(aria_valuetextAttr, newVisibleValue); 220 setAttribute(aria_valuenowAttr, String::number(valueForARIAValueNow())); 221 } else { 222 setAttribute(aria_valuetextAttr, AXDateTimeFieldEmptyValueText()); 223 removeAttribute(aria_valuenowAttr); 224 } 225 226 if (eventBehavior == DispatchEvent && m_fieldOwner) 227 m_fieldOwner->fieldValueChanged(); 228 } 229 230 int DateTimeFieldElement::valueForARIAValueNow() const 231 { 232 return valueAsInteger(); 233 } 234 235 } // namespace WebCore 236 237 #endif 238