summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLInputElement.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-01-05 12:15:11 +0000
committerSteve Block <steveblock@google.com>2011-01-06 14:14:00 +0000
commitd06194330da2bb8da887d2e1adeacb3a5c1504b2 (patch)
treee0af8413af65a8e30630563441af7bdb8478e513 /WebCore/html/HTMLInputElement.cpp
parent419a5cf2f8db6ca014df624865197ffb82caad37 (diff)
downloadexternal_webkit-d06194330da2bb8da887d2e1adeacb3a5c1504b2.zip
external_webkit-d06194330da2bb8da887d2e1adeacb3a5c1504b2.tar.gz
external_webkit-d06194330da2bb8da887d2e1adeacb3a5c1504b2.tar.bz2
Merge WebKit at r72805: Initial merge by Git
Note that this is a backwards merge from Chromium release 9.0.600.0 to 9.0.597.0, to align with the Chromium 9 stable release branch. Change-Id: I5d2bb4e8cee9d39ae8485abf48bdb55ecf8b3790
Diffstat (limited to 'WebCore/html/HTMLInputElement.cpp')
-rw-r--r--WebCore/html/HTMLInputElement.cpp283
1 files changed, 190 insertions, 93 deletions
diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp
index 765e4fc..7449098 100644
--- a/WebCore/html/HTMLInputElement.cpp
+++ b/WebCore/html/HTMLInputElement.cpp
@@ -784,7 +784,7 @@ void HTMLInputElement::parseMappedAttribute(Attribute* attr)
#if ENABLE(INPUT_SPEECH)
else if (attr->name() == webkitspeechAttr) {
if (renderer())
- toRenderTextControlSingleLine(renderer())->speechAttributeChanged();
+ renderer()->updateFromElement();
setNeedsStyleRecalc();
} else if (attr->name() == onwebkitspeechchangeAttr)
setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, attr));
@@ -1303,6 +1303,11 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
// FIXME: It would be better to refactor this for the different types of input element.
// Having them all in one giant function makes this hard to read, and almost all the handling is type-specific.
+ bool implicitSubmission = false;
+
+ if (isTextField() && evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n")
+ implicitSubmission = true;
+
if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && m_inputType->handleClickEvent(static_cast<MouseEvent*>(evt)))
return;
@@ -1311,7 +1316,8 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
// Call the base event handler before any of our own event handling for almost all events in text fields.
// Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
- bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
+ bool callBaseClassEarly = isTextField() && !implicitSubmission
+ && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
if (callBaseClassEarly) {
HTMLFormControlElementWithState::defaultEventHandler(evt);
if (evt->defaultHandled())
@@ -1327,13 +1333,180 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
// Use key press event here since sending simulated mouse events
// on key down blocks the proper sending of the key press event.
- if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent && m_inputType->handleKeypressEvent(static_cast<KeyboardEvent*>(evt)))
- return;
+ if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) {
+ bool clickElement = false;
+
+ int charCode = static_cast<KeyboardEvent*>(evt)->charCode();
+
+ if (charCode == '\r') {
+ switch (deprecatedInputType()) {
+ case CHECKBOX:
+ case COLOR:
+ case DATE:
+ case DATETIME:
+ case DATETIMELOCAL:
+ case EMAIL:
+ case HIDDEN:
+ case ISINDEX:
+ case MONTH:
+ case NUMBER:
+ case PASSWORD:
+ case RADIO:
+ case RANGE:
+ case SEARCH:
+ case TELEPHONE:
+ case TEXT:
+ case TIME:
+ case URL:
+ case WEEK:
+ // Simulate mouse click on the default form button for enter for these types of elements.
+ implicitSubmission = true;
+ break;
+ case BUTTON:
+ case FILE:
+ case IMAGE:
+ case RESET:
+ case SUBMIT:
+ // Simulate mouse click for enter for these types of elements.
+ clickElement = true;
+ break;
+ }
+ } else if (charCode == ' ') {
+ switch (deprecatedInputType()) {
+ case BUTTON:
+ case CHECKBOX:
+ case FILE:
+ case IMAGE:
+ case RESET:
+ case SUBMIT:
+ case RADIO:
+ // Prevent scrolling down the page.
+ evt->setDefaultHandled();
+ return;
+ default:
+ break;
+ }
+ }
- if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent && m_inputType->handleKeyupEvent(static_cast<KeyboardEvent*>(evt)))
- return;
+ if (clickElement) {
+ dispatchSimulatedClick(evt);
+ evt->setDefaultHandled();
+ return;
+ }
+ }
+
+ if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) {
+ const String& key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
+
+ if (key == "U+0020") {
+ switch (deprecatedInputType()) {
+ case BUTTON:
+ case CHECKBOX:
+ case FILE:
+ case IMAGE:
+ case RESET:
+ case SUBMIT:
+ case RADIO:
+ setActive(true, true);
+ // No setDefaultHandled(), because IE dispatches a keypress in this case
+ // and the caller will only dispatch a keypress if we don't call setDefaultHandled.
+ return;
+ default:
+ break;
+ }
+ }
+
+ if (deprecatedInputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) {
+ // Left and up mean "previous radio button".
+ // Right and down mean "next radio button".
+ // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves
+ // to the right). Seems strange, but we'll match it.
+ // However, when using Spatial Navigation, we need to be able to navigate without changing the selection.
+ if (!isSpatialNavigationEnabled(document()->frame())) {
+ bool forward = (key == "Down" || key == "Right");
+
+ // We can only stay within the form's children if the form hasn't been demoted to a leaf because
+ // of malformed HTML.
+ Node* n = this;
+ while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) {
+ // Once we encounter a form element, we know we're through.
+ if (n->hasTagName(formTag))
+ break;
+
+ // Look for more radio buttons.
+ if (n->hasTagName(inputTag)) {
+ HTMLInputElement* elt = static_cast<HTMLInputElement*>(n);
+ if (elt->form() != form())
+ break;
+ if (n->hasTagName(inputTag)) {
+ HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n);
+ if (inputElt->deprecatedInputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) {
+ inputElt->setChecked(true);
+ document()->setFocusedNode(inputElt);
+ inputElt->dispatchSimulatedClick(evt, false, false);
+ evt->setDefaultHandled();
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (evt->type() == eventNames().keyupEvent && evt->isKeyboardEvent()) {
+ bool clickElement = false;
+
+ const String& key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
+
+ if (key == "U+0020") {
+ switch (deprecatedInputType()) {
+ case BUTTON:
+ case CHECKBOX:
+ case FILE:
+ case IMAGE:
+ case RESET:
+ case SUBMIT:
+ // Simulate mouse click for spacebar for these types of elements.
+ // The AppKit already does this for some, but not all, of them.
+ clickElement = true;
+ break;
+ case RADIO:
+ // If an unselected radio is tabbed into (because the entire group has nothing
+ // checked, or because of some explicit .focus() call), then allow space to check it.
+ if (!checked())
+ clickElement = true;
+ break;
+ case COLOR:
+ case DATE:
+ case DATETIME:
+ case DATETIMELOCAL:
+ case EMAIL:
+ case HIDDEN:
+ case ISINDEX:
+ case MONTH:
+ case NUMBER:
+ case PASSWORD:
+ case RANGE:
+ case SEARCH:
+ case TELEPHONE:
+ case TEXT:
+ case TIME:
+ case URL:
+ case WEEK:
+ break;
+ }
+ }
- if (m_inputType->shouldSubmitImplicitly(evt)) {
+ if (clickElement) {
+ if (active())
+ dispatchSimulatedClick(evt);
+ evt->setDefaultHandled();
+ return;
+ }
+ }
+
+ if (implicitSubmission) {
if (isSearchField()) {
addSearchResult();
onSearch();
@@ -1697,113 +1870,37 @@ HTMLOptionElement* HTMLInputElement::selectedOption() const
void HTMLInputElement::stepUpFromRenderer(int n)
{
// The differences from stepUp()/stepDown():
- //
- // 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 -step if n < 0
- // If -step or +step is out of range, new value should be 0.
- // * If 0 is smaller than the minimum value
- // - The value should be the minimum value for any n
- // * If 0 is larger than the maximum value
- // - The value should be the maximum value for any n
- // * If 0 is in-range, but not matched to step value
- // - The value should be the larger matched value nearest to 0 if n > 0
- // e.g. <input type=number min=-100 step=3> -> 2
- // - The value should be the smaler matched value nearest to 0 if n < 0
- // e.g. <input type=number min=-100 step=3> -> -1
- // As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time".
- // As for datetime type, the current value is assumed as "the current date/time in UTC".
+ // If the current value is not a number, the value will be
+ // - The value should be the minimum value if n > 0
+ // - The value should be the maximum value if n < 0
// If the current value is smaller than the minimum value:
// - The value should be the minimum value if n > 0
// - Nothing should happen if n < 0
// If the current value is larger than the maximum value:
// - 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(hasSpinButton() || m_inputType->isRangeControl());
- if (!hasSpinButton() && !m_inputType->isRangeControl())
+
+ ASSERT(hasSpinButton());
+ if (!hasSpinButton())
return;
ASSERT(n);
if (!n)
return;
- unsigned stepDecimalPlaces, baseDecimalPlaces;
- double step, base;
- // The value will be the default value after stepping for <input value=(empty/invalid) step="any" />
- // FIXME: Not any changes after stepping, even if it is an invalid value, may be better.
- // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo")
- if (equalIgnoringCase(getAttribute(stepAttr), "any"))
- step = 0;
- else if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces))
- return;
- base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces);
- baseDecimalPlaces = min(baseDecimalPlaces, 16u);
-
- int sign;
- if (step > 0)
- sign = n;
- else if (step < 0)
- sign = -n;
- else
- sign = 0;
-
const double nan = numeric_limits<double>::quiet_NaN();
String currentStringValue = value();
double current = m_inputType->parseToDouble(currentStringValue, nan);
- if (!isfinite(current)) {
- ExceptionCode ec;
- current = m_inputType->defaultValueForStepUp();
- setValueAsNumber(current, ec);
- }
- if ((sign > 0 && current < m_inputType->minimum()) || (sign < 0 && current > m_inputType->maximum()))
- setValue(m_inputType->serialize(sign > 0 ? m_inputType->minimum() : m_inputType->maximum()));
+ if (!isfinite(current) || (n > 0 && current < m_inputType->minimum()) || (n < 0 && current > m_inputType->maximum()))
+ setValue(m_inputType->serialize(n > 0 ? m_inputType->minimum() : m_inputType->maximum()));
else {
ExceptionCode ec;
- if (stepMismatch(currentStringValue)) {
- ASSERT(step);
- double newValue;
- double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces)));
-
- if (sign < 0)
- newValue = round((base + floor((current - base) / step) * step) * scale) / scale;
- else if (sign > 0)
- newValue = round((base + ceil((current - base) / step) * step) * scale) / scale;
- else
- newValue = current;
-
- if (newValue < m_inputType->minimum())
- newValue = m_inputType->minimum();
- if (newValue > m_inputType->maximum())
- newValue = m_inputType->maximum();
-
- setValueAsNumber(newValue, ec);
- current = newValue;
- if (n > 1)
- applyStep(n - 1, ec);
- else if (n < -1)
- applyStep(n + 1, ec);
- } else
- applyStep(n, ec);
+ stepUp(n, ec);
}
if (currentStringValue != value()) {
if (renderer() && renderer()->isTextField())
toRenderTextControl(renderer())->setChangedSinceLastChangeEvent(true);
- if (m_inputType->isRangeControl())
- dispatchFormControlChangeEvent();
- else
- dispatchEvent(Event::create(eventNames().inputEvent, true, false));
+ dispatchEvent(Event::create(eventNames().inputEvent, true, false));
}
}