RangeInputType.cpp [plain text]
#include "config.h"
#include "RangeInputType.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "PlatformMouseEvent.h"
#include "RenderSlider.h"
#include "ShadowRoot.h"
#include "SliderThumbElement.h"
#include "StepRange.h"
#include <limits>
#include <wtf/MathExtras.h>
#include <wtf/PassOwnPtr.h>
namespace WebCore {
using namespace HTMLNames;
using namespace std;
static const double rangeDefaultMinimum = 0.0;
static const double rangeDefaultMaximum = 100.0;
static const double rangeDefaultStep = 1.0;
static const double rangeStepScaleFactor = 1.0;
PassOwnPtr<InputType> RangeInputType::create(HTMLInputElement* element)
{
return adoptPtr(new RangeInputType(element));
}
bool RangeInputType::isRangeControl() const
{
return true;
}
const AtomicString& RangeInputType::formControlType() const
{
return InputTypeNames::range();
}
double RangeInputType::valueAsNumber() const
{
return parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN());
}
void RangeInputType::setValueAsNumber(double newValue, ExceptionCode&) const
{
element()->setValue(serialize(newValue));
}
bool RangeInputType::supportsRequired() const
{
return false;
}
bool RangeInputType::rangeUnderflow(const String& value) const
{
ASSERT_UNUSED(value, parseToDouble(value, numeric_limits<double>::quiet_NaN()) >= minimum());
return false;
}
bool RangeInputType::rangeOverflow(const String& value) const
{
ASSERT_UNUSED(value, parseToDouble(value, numeric_limits<double>::quiet_NaN()) <= maximum());
return false;
}
bool RangeInputType::supportsRangeLimitation() const
{
return true;
}
double RangeInputType::minimum() const
{
return parseToDouble(element()->fastGetAttribute(minAttr), rangeDefaultMinimum);
}
double RangeInputType::maximum() const
{
double max = parseToDouble(element()->fastGetAttribute(maxAttr), rangeDefaultMaximum);
double min = minimum();
if (max < min)
max = std::max(min, rangeDefaultMaximum);
return max;
}
bool RangeInputType::isSteppable() const
{
return true;
}
bool RangeInputType::stepMismatch(const String&, double) const
{
return false;
}
double RangeInputType::stepBase() const
{
return minimum();
}
double RangeInputType::defaultStep() const
{
return rangeDefaultStep;
}
double RangeInputType::stepScaleFactor() const
{
return rangeStepScaleFactor;
}
void RangeInputType::handleMouseDownEvent(MouseEvent* event)
{
if (event->button() != LeftButton || event->target() != element())
return;
if (SliderThumbElement* thumb = shadowSliderThumb())
thumb->dragFrom(event->absoluteLocation());
}
void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
{
if (element()->disabled() || element()->readOnly())
return;
const String& key = event->keyIdentifier();
if (key != "Up" && key != "Right" && key != "Down" && key != "Left")
return;
ExceptionCode ec;
if (equalIgnoringCase(element()->fastGetAttribute(stepAttr), "any")) {
double min = minimum();
double max = maximum();
double step = (max - min) / 100;
double current = parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN());
ASSERT(isfinite(current));
double newValue;
if (key == "Up" || key == "Right") {
newValue = current + step;
if (newValue > max)
newValue = max;
} else {
newValue = current - step;
if (newValue < min)
newValue = min;
}
if (newValue != current) {
setValueAsNumber(newValue, ec);
element()->dispatchFormControlChangeEvent();
}
} else {
int stepMagnification = (key == "Up" || key == "Right") ? 1 : -1;
element()->stepUpFromRenderer(stepMagnification);
}
event->setDefaultHandled();
}
void RangeInputType::createShadowSubtree()
{
ExceptionCode ec = 0;
element()->ensureShadowRoot()->appendChild(SliderThumbElement::create(element()->document()), ec);
}
RenderObject* RangeInputType::createRenderer(RenderArena* arena, RenderStyle*) const
{
return new (arena) RenderSlider(element());
}
double RangeInputType::parseToDouble(const String& src, double defaultValue) const
{
double numberValue;
if (!parseToDoubleForNumberType(src, &numberValue))
return defaultValue;
ASSERT(isfinite(numberValue));
return numberValue;
}
String RangeInputType::serialize(double value) const
{
if (!isfinite(value))
return String();
return serializeForNumberType(value);
}
void RangeInputType::accessKeyAction(bool sendToAnyElement)
{
InputType::accessKeyAction(sendToAnyElement);
element()->dispatchSimulatedClick(0, sendToAnyElement);
}
void RangeInputType::minOrMaxAttributeChanged()
{
InputType::minOrMaxAttributeChanged();
element()->setValue(element()->value());
element()->setNeedsStyleRecalc();
}
void RangeInputType::valueChanged()
{
shadowSliderThumb()->setPositionFromValue();
}
String RangeInputType::fallbackValue()
{
return serializeForNumberType(StepRange(element()).defaultValue());
}
String RangeInputType::sanitizeValue(const String& proposedValue)
{
if (proposedValue.isNull())
return proposedValue;
return serializeForNumberType(StepRange(element()).clampValue(proposedValue));
}
bool RangeInputType::shouldRespectListAttribute()
{
return true;
}
SliderThumbElement* RangeInputType::shadowSliderThumb() const
{
Node* shadow = element()->shadowRoot();
return shadow ? toSliderThumbElement(shadow->firstChild()) : 0;
}
}