2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7 * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
8 * Copyright (C) 2009, 2010, 2011, 2012 Google Inc. All rights reserved.
9 * Copyright (C) 2012 Samsung Electronics. All rights reserved.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
29 #include "core/html/forms/InputType.h"
31 #include "InputTypeNames.h"
32 #include "RuntimeEnabledFeatures.h"
33 #include "bindings/v8/ExceptionMessages.h"
34 #include "bindings/v8/ExceptionState.h"
35 #include "core/accessibility/AXObjectCache.h"
36 #include "core/dom/NodeRenderStyle.h"
37 #include "core/events/KeyboardEvent.h"
38 #include "core/events/ScopedEventQueue.h"
39 #include "core/fileapi/FileList.h"
40 #include "core/frame/FrameHost.h"
41 #include "core/html/FormDataList.h"
42 #include "core/html/HTMLInputElement.h"
43 #include "core/html/forms/ButtonInputType.h"
44 #include "core/html/forms/CheckboxInputType.h"
45 #include "core/html/forms/ColorInputType.h"
46 #include "core/html/forms/DateInputType.h"
47 #include "core/html/forms/DateTimeLocalInputType.h"
48 #include "core/html/forms/EmailInputType.h"
49 #include "core/html/forms/FileInputType.h"
50 #include "core/html/forms/FormController.h"
51 #include "core/html/forms/HiddenInputType.h"
52 #include "core/html/forms/ImageInputType.h"
53 #include "core/html/forms/MonthInputType.h"
54 #include "core/html/forms/NumberInputType.h"
55 #include "core/html/forms/PasswordInputType.h"
56 #include "core/html/forms/RadioInputType.h"
57 #include "core/html/forms/RangeInputType.h"
58 #include "core/html/forms/ResetInputType.h"
59 #include "core/html/forms/SearchInputType.h"
60 #include "core/html/forms/SubmitInputType.h"
61 #include "core/html/forms/TelephoneInputType.h"
62 #include "core/html/forms/TextInputType.h"
63 #include "core/html/forms/TimeInputType.h"
64 #include "core/html/forms/URLInputType.h"
65 #include "core/html/forms/WeekInputType.h"
66 #include "core/html/parser/HTMLParserIdioms.h"
67 #include "core/html/shadow/HTMLShadowElement.h"
68 #include "core/rendering/RenderTheme.h"
69 #include "platform/text/PlatformLocale.h"
70 #include "platform/text/TextBreakIterator.h"
74 using blink::WebLocalizedString;
75 using namespace HTMLNames;
78 typedef PassRefPtr<InputType> (*InputTypeFactoryFunction)(HTMLInputElement&);
79 typedef HashMap<AtomicString, InputTypeFactoryFunction, CaseFoldingHash> InputTypeFactoryMap;
81 static PassOwnPtr<InputTypeFactoryMap> createInputTypeFactoryMap()
83 OwnPtr<InputTypeFactoryMap> map = adoptPtr(new InputTypeFactoryMap);
84 map->add(InputTypeNames::button, ButtonInputType::create);
85 map->add(InputTypeNames::checkbox, CheckboxInputType::create);
86 map->add(InputTypeNames::color, ColorInputType::create);
87 map->add(InputTypeNames::date, DateInputType::create);
88 map->add(InputTypeNames::datetime_local, DateTimeLocalInputType::create);
89 map->add(InputTypeNames::email, EmailInputType::create);
90 map->add(InputTypeNames::file, FileInputType::create);
91 map->add(InputTypeNames::hidden, HiddenInputType::create);
92 map->add(InputTypeNames::image, ImageInputType::create);
93 map->add(InputTypeNames::month, MonthInputType::create);
94 map->add(InputTypeNames::number, NumberInputType::create);
95 map->add(InputTypeNames::password, PasswordInputType::create);
96 map->add(InputTypeNames::radio, RadioInputType::create);
97 map->add(InputTypeNames::range, RangeInputType::create);
98 map->add(InputTypeNames::reset, ResetInputType::create);
99 map->add(InputTypeNames::search, SearchInputType::create);
100 map->add(InputTypeNames::submit, SubmitInputType::create);
101 map->add(InputTypeNames::tel, TelephoneInputType::create);
102 map->add(InputTypeNames::time, TimeInputType::create);
103 map->add(InputTypeNames::url, URLInputType::create);
104 map->add(InputTypeNames::week, WeekInputType::create);
105 // No need to register "text" because it is the default type.
106 return map.release();
109 static const InputTypeFactoryMap* factoryMap()
111 static const InputTypeFactoryMap* factoryMap = createInputTypeFactoryMap().leakPtr();
115 PassRefPtr<InputType> InputType::create(HTMLInputElement& element, const AtomicString& typeName)
117 InputTypeFactoryFunction factory = typeName.isEmpty() ? 0 : factoryMap()->get(typeName);
119 factory = TextInputType::create;
120 return factory(element);
123 PassRefPtr<InputType> InputType::createText(HTMLInputElement& element)
125 return TextInputType::create(element);
128 const AtomicString& InputType::normalizeTypeName(const AtomicString& typeName)
130 if (typeName.isEmpty())
131 return InputTypeNames::text;
132 InputTypeFactoryMap::const_iterator it = factoryMap()->find(typeName);
133 return it == factoryMap()->end() ? InputTypeNames::text : it->key;
136 bool InputType::canChangeFromAnotherType(const AtomicString& normalizedTypeName)
138 // Don't allow the type to be changed to file after the first type change.
139 // In other engines this might mean a JavaScript programmer could set a text
140 // field's value to something like /etc/passwd and then change it to a file
141 // input. I don't think this would actually occur in Blink, but this rule
142 // still may be important for compatibility.
143 return normalizedTypeName != InputTypeNames::file;
146 InputType::~InputType()
150 bool InputType::themeSupportsDataListUI(InputType* type)
152 return RenderTheme::theme().supportsDataListUI(type->formControlType());
155 bool InputType::isTextField() const
160 bool InputType::isTextType() const
165 bool InputType::isRangeControl() const
170 bool InputType::shouldSaveAndRestoreFormControlState() const
175 FormControlState InputType::saveFormControlState() const
177 String currentValue = element().value();
178 if (currentValue == element().defaultValue())
179 return FormControlState();
180 return FormControlState(currentValue);
183 void InputType::restoreFormControlState(const FormControlState& state)
185 element().setValue(state[0]);
188 bool InputType::isFormDataAppendable() const
190 // There is no form data unless there's a name for non-image types.
191 return !element().name().isEmpty();
194 bool InputType::appendFormData(FormDataList& encoding, bool) const
196 // Always successful.
197 encoding.appendData(element().name(), element().value());
201 String InputType::resultForDialogSubmit() const
203 return element().fastGetAttribute(valueAttr);
206 double InputType::valueAsDate() const
208 return DateComponents::invalidMilliseconds();
211 void InputType::setValueAsDate(double, ExceptionState& exceptionState) const
213 exceptionState.throwDOMException(InvalidStateError, "This input element does not support Date values.");
216 double InputType::valueAsDouble() const
218 return numeric_limits<double>::quiet_NaN();
221 void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState) const
223 exceptionState.throwDOMException(InvalidStateError, "This input element does not support Number values.");
226 void InputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionState&) const
228 element().setValue(serialize(newValue), eventBehavior);
231 bool InputType::supportsValidation() const
236 bool InputType::typeMismatchFor(const String&) const
241 bool InputType::typeMismatch() const
246 bool InputType::supportsRequired() const
248 // Almost all validatable types support @required.
249 return supportsValidation();
252 bool InputType::valueMissing(const String&) const
257 bool InputType::hasBadInput() const
262 bool InputType::patternMismatch(const String&) const
267 bool InputType::rangeUnderflow(const String& value) const
272 const Decimal numericValue = parseToNumberOrNaN(value);
273 if (!numericValue.isFinite())
276 return numericValue < createStepRange(RejectAny).minimum();
279 bool InputType::rangeOverflow(const String& value) const
284 const Decimal numericValue = parseToNumberOrNaN(value);
285 if (!numericValue.isFinite())
288 return numericValue > createStepRange(RejectAny).maximum();
291 Decimal InputType::defaultValueForStepUp() const
296 double InputType::minimum() const
298 return createStepRange(RejectAny).minimum().toDouble();
301 double InputType::maximum() const
303 return createStepRange(RejectAny).maximum().toDouble();
306 bool InputType::isInRange(const String& value) const
311 const Decimal numericValue = parseToNumberOrNaN(value);
312 if (!numericValue.isFinite())
315 StepRange stepRange(createStepRange(RejectAny));
316 return numericValue >= stepRange.minimum() && numericValue <= stepRange.maximum();
319 bool InputType::isOutOfRange(const String& value) const
324 const Decimal numericValue = parseToNumberOrNaN(value);
325 if (!numericValue.isFinite())
328 StepRange stepRange(createStepRange(RejectAny));
329 return numericValue < stepRange.minimum() || numericValue > stepRange.maximum();
332 bool InputType::stepMismatch(const String& value) const
337 const Decimal numericValue = parseToNumberOrNaN(value);
338 if (!numericValue.isFinite())
341 return createStepRange(RejectAny).stepMismatch(numericValue);
344 String InputType::badInputText() const
346 ASSERT_NOT_REACHED();
347 return locale().queryString(WebLocalizedString::ValidationTypeMismatch);
350 String InputType::rangeOverflowText(const Decimal&) const
352 ASSERT_NOT_REACHED();
356 String InputType::rangeUnderflowText(const Decimal&) const
358 ASSERT_NOT_REACHED();
362 String InputType::typeMismatchText() const
364 return locale().queryString(WebLocalizedString::ValidationTypeMismatch);
367 String InputType::valueMissingText() const
369 return locale().queryString(WebLocalizedString::ValidationValueMissing);
372 String InputType::validationMessage() const
374 const String value = element().value();
376 // The order of the following checks is meaningful. e.g. We'd like to show the
377 // badInput message even if the control has other validation errors.
379 return badInputText();
381 if (valueMissing(value))
382 return valueMissingText();
385 return typeMismatchText();
387 if (patternMismatch(value))
388 return locale().queryString(WebLocalizedString::ValidationPatternMismatch);
390 if (element().tooLong())
391 return locale().validationMessageTooLongText(value.length(), element().maxLength());
394 return emptyString();
396 const Decimal numericValue = parseToNumberOrNaN(value);
397 if (!numericValue.isFinite())
398 return emptyString();
400 StepRange stepRange(createStepRange(RejectAny));
402 if (numericValue < stepRange.minimum())
403 return rangeUnderflowText(stepRange.minimum());
405 if (numericValue > stepRange.maximum())
406 return rangeOverflowText(stepRange.maximum());
408 if (stepRange.stepMismatch(numericValue)) {
409 ASSERT(stepRange.hasStep());
410 Decimal candidate1 = stepRange.clampValue(numericValue);
411 String localizedCandidate1 = localizeValue(serialize(candidate1));
412 Decimal candidate2 = candidate1 < numericValue ? candidate1 + stepRange.step() : candidate1 - stepRange.step();
413 if (!candidate2.isFinite() || candidate2 < stepRange.minimum() || candidate2 > stepRange.maximum())
414 return locale().queryString(WebLocalizedString::ValidationStepMismatchCloseToLimit, localizedCandidate1);
415 String localizedCandidate2 = localizeValue(serialize(candidate2));
416 if (candidate1 < candidate2)
417 return locale().queryString(WebLocalizedString::ValidationStepMismatch, localizedCandidate1, localizedCandidate2);
418 return locale().queryString(WebLocalizedString::ValidationStepMismatch, localizedCandidate2, localizedCandidate1);
421 return emptyString();
424 bool InputType::shouldSubmitImplicitly(Event* event)
426 return event->isKeyboardEvent() && event->type() == EventTypeNames::keypress && toKeyboardEvent(event)->charCode() == '\r';
429 Decimal InputType::parseToNumber(const String&, const Decimal& defaultValue) const
431 ASSERT_NOT_REACHED();
435 Decimal InputType::parseToNumberOrNaN(const String& string) const
437 return parseToNumber(string, Decimal::nan());
440 String InputType::serialize(const Decimal&) const
442 ASSERT_NOT_REACHED();
446 void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const
448 if (element().active())
449 element().dispatchSimulatedClick(event);
450 event->setDefaultHandled();
453 Chrome* InputType::chrome() const
455 if (FrameHost* host = element().document().frameHost())
456 return &host->chrome();
460 Locale& InputType::locale() const
462 return element().locale();
465 bool InputType::canSetStringValue() const
470 bool InputType::hasCustomFocusLogic() const
475 bool InputType::isKeyboardFocusable() const
477 return element().isFocusable();
480 bool InputType::shouldShowFocusRingOnMouseFocus() const
485 bool InputType::shouldUseInputMethod() const
490 void InputType::enableSecureTextInput()
494 void InputType::disableSecureTextInput()
498 void InputType::accessKeyAction(bool)
500 element().focus(false);
503 void InputType::countUsage()
507 bool InputType::shouldRespectAlignAttribute()
512 void InputType::sanitizeValueInResponseToMinOrMaxAttributeChange()
516 bool InputType::canBeSuccessfulSubmitButton()
521 bool InputType::rendererIsNeeded()
526 FileList* InputType::files()
531 void InputType::setFiles(PassRefPtr<FileList>)
535 bool InputType::getTypeSpecificValue(String&)
540 String InputType::fallbackValue() const
545 String InputType::defaultValue() const
550 bool InputType::canSetSuggestedValue()
555 bool InputType::shouldSendChangeEventAfterCheckedChanged()
560 bool InputType::storesValueSeparateFromAttribute()
565 void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
567 element().setValueInternal(sanitizedValue, eventBehavior);
568 element().setNeedsStyleRecalc(SubtreeStyleChange);
571 switch (eventBehavior) {
572 case DispatchChangeEvent:
573 element().dispatchFormControlChangeEvent();
575 case DispatchInputAndChangeEvent:
576 element().dispatchFormControlInputEvent();
577 element().dispatchFormControlChangeEvent();
579 case DispatchNoEvent:
584 bool InputType::canSetValue(const String&)
589 String InputType::localizeValue(const String& proposedValue) const
591 return proposedValue;
594 String InputType::visibleValue() const
596 return element().value();
599 String InputType::sanitizeValue(const String& proposedValue) const
601 return proposedValue;
604 bool InputType::receiveDroppedFiles(const DragData*)
606 ASSERT_NOT_REACHED();
610 String InputType::droppedFileSystemId()
612 ASSERT_NOT_REACHED();
616 bool InputType::shouldRespectListAttribute()
621 bool InputType::shouldRespectSpeechAttribute()
626 bool InputType::isTextButton() const
631 bool InputType::isRadioButton() const
636 bool InputType::isSearchField() const
641 bool InputType::isHiddenType() const
646 bool InputType::isPasswordField() const
651 bool InputType::isCheckbox() const
656 bool InputType::isEmailField() const
661 bool InputType::isFileUpload() const
666 bool InputType::isImageButton() const
671 bool InputType::isInteractiveContent() const
676 bool InputType::isNumberField() const
681 bool InputType::isTelephoneField() const
686 bool InputType::isURLField() const
691 bool InputType::isDateField() const
696 bool InputType::isDateTimeLocalField() const
701 bool InputType::isMonthField() const
706 bool InputType::isTimeField() const
711 bool InputType::isWeekField() const
716 bool InputType::isEnumeratable()
721 bool InputType::isCheckable()
726 bool InputType::isSteppable() const
731 bool InputType::isColorControl() const
736 bool InputType::shouldRespectHeightAndWidthAttributes()
741 bool InputType::supportsPlaceholder() const
746 bool InputType::supportsReadOnly() const
751 String InputType::defaultToolTip() const
756 Decimal InputType::findClosestTickMarkValue(const Decimal&)
758 ASSERT_NOT_REACHED();
759 return Decimal::nan();
762 void InputType::handleDOMActivateEvent(Event*)
766 bool InputType::supportsIndeterminateAppearance() const
771 bool InputType::supportsInputModeAttribute() const
776 bool InputType::supportsSelectionAPI() const
781 unsigned InputType::height() const
786 unsigned InputType::width() const
791 void InputType::applyStep(const Decimal& current, int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState)
793 StepRange stepRange(createStepRange(anyStepHandling));
794 if (!stepRange.hasStep()) {
795 exceptionState.throwDOMException(InvalidStateError, "This form element does not have an allowed value step.");
799 EventQueueScope scope;
800 const Decimal step = stepRange.step();
802 const AtomicString& stepString = element().fastGetAttribute(stepAttr);
803 if (!equalIgnoringCase(stepString, "any") && stepRange.stepMismatch(current)) {
804 // Snap-to-step / clamping steps
805 // If the current value is not matched to step value:
806 // - The value should be the larger matched value nearest to 0 if count > 0
807 // e.g. <input type=number value=3 min=-100 step=3> -> 5
808 // - The value should be the smaller matched value nearest to 0 if count < 0
809 // e.g. <input type=number value=3 min=-100 step=3> -> 2
812 ASSERT(!step.isZero());
814 const Decimal base = stepRange.stepBase();
816 newValue = base + ((current - base) / step).floor() * step;
818 newValue = base + ((current - base) / step).ceiling() * step;
822 if (newValue < stepRange.minimum())
823 newValue = stepRange.minimum();
824 if (newValue > stepRange.maximum())
825 newValue = stepRange.maximum();
827 setValueAsDecimal(newValue, count == 1 || count == -1 ? DispatchChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
829 applyStep(newValue, count - 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
833 applyStep(newValue, count + 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
837 Decimal newValue = current + stepRange.step() * count;
839 if (!equalIgnoringCase(stepString, "any"))
840 newValue = stepRange.alignValueForStep(current, newValue);
842 if (newValue > stepRange.maximum())
843 newValue = newValue - stepRange.step();
844 else if (newValue < stepRange.minimum())
845 newValue = newValue + stepRange.step();
847 setValueAsDecimal(newValue, eventBehavior, exceptionState);
849 if (AXObjectCache* cache = element().document().existingAXObjectCache())
850 cache->postNotification(&element(), AXObjectCache::AXValueChanged, true);
853 bool InputType::getAllowedValueStep(Decimal* step) const
855 StepRange stepRange(createStepRange(RejectAny));
856 *step = stepRange.step();
857 return stepRange.hasStep();
860 StepRange InputType::createStepRange(AnyStepHandling) const
862 ASSERT_NOT_REACHED();
866 void InputType::stepUp(int n, ExceptionState& exceptionState)
868 if (!isSteppable()) {
869 exceptionState.throwDOMException(InvalidStateError, "This form element is not steppable.");
872 const Decimal current = parseToNumber(element().value(), 0);
873 applyStep(current, n, RejectAny, DispatchNoEvent, exceptionState);
876 void InputType::stepUpFromRenderer(int n)
878 // The only difference from stepUp()/stepDown() is the extra treatment
879 // of the current value before applying the step:
881 // If the current value is not a number, including empty, the current value is assumed as 0.
882 // * If 0 is in-range, and matches to step value
883 // - The value should be the +step if n > 0
884 // - The value should be the -step if n < 0
885 // If -step or +step is out of range, new value should be 0.
886 // * If 0 is smaller than the minimum value
887 // - The value should be the minimum value for any n
888 // * If 0 is larger than the maximum value
889 // - The value should be the maximum value for any n
890 // * If 0 is in-range, but not matched to step value
891 // - The value should be the larger matched value nearest to 0 if n > 0
892 // e.g. <input type=number min=-100 step=3> -> 2
893 // - The value should be the smaler matched value nearest to 0 if n < 0
894 // e.g. <input type=number min=-100 step=3> -> -1
895 // As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time".
896 // As for datetime type, the current value is assumed as "the current date/time in UTC".
897 // If the current value is smaller than the minimum value:
898 // - The value should be the minimum value if n > 0
899 // - Nothing should happen if n < 0
900 // If the current value is larger than the maximum value:
901 // - The value should be the maximum value if n < 0
902 // - Nothing should happen if n > 0
904 // n is assumed as -n if step < 0.
906 ASSERT(isSteppable());
913 StepRange stepRange(createStepRange(AnyIsDefaultStep));
915 // FIXME: Not any changes after stepping, even if it is an invalid value, may be better.
916 // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo")
917 if (!stepRange.hasStep())
920 EventQueueScope scope;
921 const Decimal step = stepRange.step();
931 Decimal current = parseToNumberOrNaN(element().value());
932 if (!current.isFinite()) {
933 current = defaultValueForStepUp();
934 const Decimal nextDiff = step * n;
935 if (current < stepRange.minimum() - nextDiff)
936 current = stepRange.minimum() - nextDiff;
937 if (current > stepRange.maximum() - nextDiff)
938 current = stepRange.maximum() - nextDiff;
939 setValueAsDecimal(current, DispatchNoEvent, IGNORE_EXCEPTION);
941 if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum())) {
942 setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
945 applyStep(current, n, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
948 void InputType::countUsageIfVisible(UseCounter::Feature feature) const
950 if (RenderStyle* style = element().renderStyle()) {
951 if (style->visibility() != HIDDEN)
952 UseCounter::count(element().document(), feature);
956 Decimal InputType::findStepBase(const Decimal& defaultValue) const
958 Decimal stepBase = parseToNumber(element().fastGetAttribute(minAttr), Decimal::nan());
959 if (!stepBase.isFinite())
960 stepBase = parseToNumber(element().fastGetAttribute(valueAttr), defaultValue);
964 StepRange InputType::createStepRange(AnyStepHandling anyStepHandling, const Decimal& stepBaseDefault, const Decimal& minimumDefault, const Decimal& maximumDefault, const StepRange::StepDescription& stepDescription) const
966 const Decimal stepBase = findStepBase(stepBaseDefault);
967 const Decimal minimum = parseToNumber(element().fastGetAttribute(minAttr), minimumDefault);
968 const Decimal maximum = parseToNumber(element().fastGetAttribute(maxAttr), maximumDefault);
969 const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element().fastGetAttribute(stepAttr));
970 return StepRange(stepBase, minimum, maximum, step, stepDescription);
973 } // namespace WebCore