OwnPtr<InputTypeFactoryMap> map = adoptPtr(new InputTypeFactoryMap);
map->add(InputTypeNames::button, ButtonInputType::create);
map->add(InputTypeNames::checkbox, CheckboxInputType::create);
- if (RuntimeEnabledFeatures::inputTypeColorEnabled())
- map->add(InputTypeNames::color, ColorInputType::create);
+ map->add(InputTypeNames::color, ColorInputType::create);
map->add(InputTypeNames::date, DateInputType::create);
map->add(InputTypeNames::datetime_local, DateTimeLocalInputType::create);
map->add(InputTypeNames::email, EmailInputType::create);
map->add(InputTypeNames::tel, TelephoneInputType::create);
map->add(InputTypeNames::time, TimeInputType::create);
map->add(InputTypeNames::url, URLInputType::create);
- if (RuntimeEnabledFeatures::inputTypeWeekEnabled())
- map->add(InputTypeNames::week, WeekInputType::create);
+ map->add(InputTypeNames::week, WeekInputType::create);
// No need to register "text" because it is the default type.
return map.release();
}
void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState) const
{
- setValueAsDecimal(Decimal::fromDouble(doubleValue), eventBehavior, exceptionState);
+ exceptionState.throwDOMException(InvalidStateError, "This input element does not support Number values.");
}
-void InputType::setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionState& exceptionState) const
+void InputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionState&) const
{
- exceptionState.throwDOMException(InvalidStateError, "This input element does not support Decimal values.");
+ element().setValue(serialize(newValue), eventBehavior);
}
bool InputType::supportsValidation() const
void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
{
element().setValueInternal(sanitizedValue, eventBehavior);
- element().setNeedsStyleRecalc();
+ element().setNeedsStyleRecalc(SubtreeStyleChange);
if (!valueChanged)
return;
switch (eventBehavior) {
return false;
}
-void InputType::updatePlaceholderText()
-{
-}
-
String InputType::defaultToolTip() const
{
return String();
return 0;
}
-void InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState)
+void InputType::applyStep(const Decimal& current, int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState)
{
StepRange stepRange(createStepRange(anyStepHandling));
if (!stepRange.hasStep()) {
return;
}
- const Decimal current = parseToNumberOrNaN(element().value());
- if (!current.isFinite()) {
- exceptionState.throwDOMException(InvalidStateError, ExceptionMessages::notAFiniteNumber(current, "form element's current value"));
- return;
- }
- Decimal newValue = current + stepRange.step() * count;
- if (!newValue.isFinite()) {
- exceptionState.throwDOMException(InvalidStateError, ExceptionMessages::notAFiniteNumber(newValue, "form element's new value"));
- return;
- }
-
- const Decimal acceptableErrorValue = stepRange.acceptableError();
- if (newValue - stepRange.minimum() < -acceptableErrorValue) {
- exceptionState.throwDOMException(InvalidStateError, "The form element's new value (" + newValue.toString() + ") would be lower than the minimum (" + stepRange.minimum().toString() + "), and snapping to the minimum would exceed the amount of acceptible error.");
- return;
- }
- if (newValue < stepRange.minimum())
- newValue = stepRange.minimum();
+ EventQueueScope scope;
+ const Decimal step = stepRange.step();
const AtomicString& stepString = element().fastGetAttribute(stepAttr);
- if (!equalIgnoringCase(stepString, "any"))
- newValue = stepRange.alignValueForStep(current, newValue);
+ if (!equalIgnoringCase(stepString, "any") && stepRange.stepMismatch(current)) {
+ // Snap-to-step / clamping steps
+ // If the current value is not matched to step value:
+ // - The value should be the larger matched value nearest to 0 if count > 0
+ // e.g. <input type=number value=3 min=-100 step=3> -> 5
+ // - The value should be the smaller matched value nearest to 0 if count < 0
+ // e.g. <input type=number value=3 min=-100 step=3> -> 2
+ //
+
+ ASSERT(!step.isZero());
+ Decimal newValue;
+ const Decimal base = stepRange.stepBase();
+ if (count < 0)
+ newValue = base + ((current - base) / step).floor() * step;
+ else if (count > 0)
+ newValue = base + ((current - base) / step).ceiling() * step;
+ else
+ newValue = current;
+
+ if (newValue < stepRange.minimum())
+ newValue = stepRange.minimum();
+ if (newValue > stepRange.maximum())
+ newValue = stepRange.maximum();
+
+ setValueAsDecimal(newValue, count == 1 || count == -1 ? DispatchChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
+ if (count > 1) {
+ applyStep(newValue, count - 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
+ return;
+ }
+ if (count < -1) {
+ applyStep(newValue, count + 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
+ return;
+ }
+ } else {
+ Decimal newValue = current + stepRange.step() * count;
- if (newValue - stepRange.maximum() > acceptableErrorValue) {
- exceptionState.throwDOMException(InvalidStateError, "The form element's new value (" + newValue.toString() + ") would be higher than the maximum (" + stepRange.maximum().toString() + "), and snapping to the maximum would exceed the amount of acceptible error.");
- return;
- }
- if (newValue > stepRange.maximum())
- newValue = stepRange.maximum();
+ if (!equalIgnoringCase(stepString, "any"))
+ newValue = stepRange.alignValueForStep(current, newValue);
- setValueAsDecimal(newValue, eventBehavior, exceptionState);
+ if (newValue > stepRange.maximum())
+ newValue = newValue - stepRange.step();
+ else if (newValue < stepRange.minimum())
+ newValue = newValue + stepRange.step();
+ setValueAsDecimal(newValue, eventBehavior, exceptionState);
+ }
if (AXObjectCache* cache = element().document().existingAXObjectCache())
cache->postNotification(&element(), AXObjectCache::AXValueChanged, true);
}
exceptionState.throwDOMException(InvalidStateError, "This form element is not steppable.");
return;
}
- applyStep(n, RejectAny, DispatchNoEvent, exceptionState);
+ const Decimal current = parseToNumber(element().value(), 0);
+ applyStep(current, n, RejectAny, DispatchNoEvent, exceptionState);
}
void InputType::stepUpFromRenderer(int n)
{
- // The differences from stepUp()/stepDown():
+ // The only difference from stepUp()/stepDown() is the extra treatment
+ // of the current value before applying the step:
//
- // Difference 1: the current value
// If the current value is not a number, including empty, the current value is assumed as 0.
// * If 0 is in-range, and matches to step value
// - The value should be the +step if n > 0
// - The value should be the maximum value if n < 0
// - Nothing should happen if n > 0
//
- // Difference 2: clamping steps
- // If the current value is not matched to step value:
- // - The value should be the larger matched value nearest to 0 if n > 0
- // e.g. <input type=number value=3 min=-100 step=3> -> 5
- // - The value should be the smaler matched value nearest to 0 if n < 0
- // e.g. <input type=number value=3 min=-100 step=3> -> 2
- //
// n is assumed as -n if step < 0.
ASSERT(isSteppable());
else
sign = 0;
- String currentStringValue = element().value();
- Decimal current = parseToNumberOrNaN(currentStringValue);
+ Decimal current = parseToNumberOrNaN(element().value());
if (!current.isFinite()) {
current = defaultValueForStepUp();
const Decimal nextDiff = step * n;
setValueAsDecimal(current, DispatchNoEvent, IGNORE_EXCEPTION);
}
if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum())) {
- setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchChangeEvent, IGNORE_EXCEPTION);
- } else {
- if (stepMismatch(element().value())) {
- ASSERT(!step.isZero());
- const Decimal base = stepRange.stepBase();
- Decimal newValue;
- if (sign < 0)
- newValue = base + ((current - base) / step).floor() * step;
- else if (sign > 0)
- newValue = base + ((current - base) / step).ceiling() * step;
- else
- newValue = current;
-
- if (newValue < stepRange.minimum())
- newValue = stepRange.minimum();
- if (newValue > stepRange.maximum())
- newValue = stepRange.maximum();
-
- setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
- if (n > 1)
- applyStep(n - 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
- else if (n < -1)
- applyStep(n + 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
- } else {
- applyStep(n, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
- }
+ setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+ return;
}
+ applyStep(current, n, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
}
void InputType::countUsageIfVisible(UseCounter::Feature feature) const