зеркало из https://github.com/mozilla/gecko-dev.git
Bug 945784, part 1 - Fire 'input' events for <input type=number> more frequently, per the new HTML5 rules. r=smaug
This commit is contained in:
Родитель
50ab3e3db1
Коммит
a3390898c6
|
@ -2603,7 +2603,7 @@ HTMLInputElement::HandleNumberControlSpin(void* aData)
|
||||||
// anything else.
|
// anything else.
|
||||||
input->StopNumberControlSpinnerSpin();
|
input->StopNumberControlSpinnerSpin();
|
||||||
} else {
|
} else {
|
||||||
input->ApplyStep(input->mNumberControlSpinnerSpinsUp ? 1 : -1);
|
input->StepNumberControlForUserEvent(input->mNumberControlSpinnerSpinsUp ? 1 : -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3498,9 +3498,21 @@ HTMLInputElement::StopNumberControlSpinnerSpin()
|
||||||
nsRepeatService::GetInstance()->Stop(HandleNumberControlSpin, this);
|
nsRepeatService::GetInstance()->Stop(HandleNumberControlSpin, this);
|
||||||
|
|
||||||
mNumberControlSpinnerIsSpinning = false;
|
mNumberControlSpinnerIsSpinning = false;
|
||||||
|
|
||||||
|
FireChangeEventIfNeeded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection)
|
||||||
|
{
|
||||||
|
ApplyStep(aDirection);
|
||||||
|
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
|
||||||
|
static_cast<nsIDOMHTMLInputElement*>(this),
|
||||||
|
NS_LITERAL_STRING("input"), true,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
SelectTextFieldOnFocus()
|
SelectTextFieldOnFocus()
|
||||||
{
|
{
|
||||||
|
@ -3731,7 +3743,7 @@ HTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
|
||||||
// XXX we still need to allow script to call preventDefault() on the
|
// XXX we still need to allow script to call preventDefault() on the
|
||||||
// event, but right now we can't tell the difference between the editor
|
// event, but right now we can't tell the difference between the editor
|
||||||
// on script doing that (bug 930374).
|
// on script doing that (bug 930374).
|
||||||
ApplyStep(keyEvent->keyCode == NS_VK_UP ? 1 : -1);
|
StepNumberControlForUserEvent(keyEvent->keyCode == NS_VK_UP ? 1 : -1);
|
||||||
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||||
} else if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
|
} else if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
|
||||||
switch (aVisitor.mEvent->message) {
|
switch (aVisitor.mEvent->message) {
|
||||||
|
@ -3959,13 +3971,13 @@ HTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
|
||||||
switch (numberControlFrame->GetSpinButtonForPointerEvent(
|
switch (numberControlFrame->GetSpinButtonForPointerEvent(
|
||||||
aVisitor.mEvent->AsMouseEvent())) {
|
aVisitor.mEvent->AsMouseEvent())) {
|
||||||
case nsNumberControlFrame::eSpinButtonUp:
|
case nsNumberControlFrame::eSpinButtonUp:
|
||||||
ApplyStep(1);
|
StepNumberControlForUserEvent(1);
|
||||||
mNumberControlSpinnerSpinsUp = true;
|
mNumberControlSpinnerSpinsUp = true;
|
||||||
StartNumberControlSpinnerSpin();
|
StartNumberControlSpinnerSpin();
|
||||||
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||||
break;
|
break;
|
||||||
case nsNumberControlFrame::eSpinButtonDown:
|
case nsNumberControlFrame::eSpinButtonDown:
|
||||||
ApplyStep(-1);
|
StepNumberControlForUserEvent(-1);
|
||||||
mNumberControlSpinnerSpinsUp = false;
|
mNumberControlSpinnerSpinsUp = false;
|
||||||
StartNumberControlSpinnerSpin();
|
StartNumberControlSpinnerSpin();
|
||||||
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||||
|
|
|
@ -680,6 +680,7 @@ public:
|
||||||
|
|
||||||
void StartNumberControlSpinnerSpin();
|
void StartNumberControlSpinnerSpin();
|
||||||
void StopNumberControlSpinnerSpin();
|
void StopNumberControlSpinnerSpin();
|
||||||
|
void StepNumberControlForUserEvent(int32_t aDirection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The callback function used by the nsRepeatService that we use to spin the
|
* The callback function used by the nsRepeatService that we use to spin the
|
||||||
|
|
|
@ -30,6 +30,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=851780
|
||||||
<input type="radio" id="input_radio" oninput="++NonTextInput[4];"></input>
|
<input type="radio" id="input_radio" oninput="++NonTextInput[4];"></input>
|
||||||
<input type="checkbox" id="input_checkbox" oninput="++NonTextInput[5];"></input>
|
<input type="checkbox" id="input_checkbox" oninput="++NonTextInput[5];"></input>
|
||||||
<input type="range" id="input_range" oninput="++rangeInput;"></input>
|
<input type="range" id="input_range" oninput="++rangeInput;"></input>
|
||||||
|
<input type="number" id="input_number" oninput="++numberInput;"></input>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<pre id="test">
|
<pre id="test">
|
||||||
|
@ -37,6 +38,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=851780
|
||||||
|
|
||||||
/** Test for input event. This is highly based on test_change_event.html **/
|
/** Test for input event. This is highly based on test_change_event.html **/
|
||||||
|
|
||||||
|
const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
|
||||||
|
|
||||||
var textareaInput = 0;
|
var textareaInput = 0;
|
||||||
|
|
||||||
// Those are types were the input event apply.
|
// Those are types were the input event apply.
|
||||||
|
@ -48,6 +51,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=851780
|
||||||
var NonTextInput = [0, 0, 0, 0, 0, 0];
|
var NonTextInput = [0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
var rangeInput = 0;
|
var rangeInput = 0;
|
||||||
|
var numberInput = 0;
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
var MockFilePicker = SpecialPowers.MockFilePicker;
|
var MockFilePicker = SpecialPowers.MockFilePicker;
|
||||||
|
@ -177,6 +181,30 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=851780
|
||||||
synthesizeMouse(range, centerOfRangeX, centerOfRangeY, { type: "mouseup" });
|
synthesizeMouse(range, centerOfRangeX, centerOfRangeY, { type: "mouseup" });
|
||||||
is(rangeInput, 4, "Input event should be dispatched at the end of a drag");
|
is(rangeInput, 4, "Input event should be dispatched at the end of a drag");
|
||||||
|
|
||||||
|
// Tests for type='number'.
|
||||||
|
// We only test key events here since input events for mouse event changes
|
||||||
|
// are tested in test_input_number_mouse_events.html
|
||||||
|
var number = document.getElementById("input_number");
|
||||||
|
|
||||||
|
if (isDesktop) { // up/down arrow keys not supported on android/b2g
|
||||||
|
number.value = "";
|
||||||
|
number.focus();
|
||||||
|
synthesizeKey("VK_UP", {});
|
||||||
|
is(numberInput, 1, "input event should be dispatched for up/down arrow key keypress");
|
||||||
|
is(number.value, 1, "sanity check value of number control after keypress");
|
||||||
|
|
||||||
|
synthesizeKey("VK_DOWN", { type: "keydown" });
|
||||||
|
synthesizeKey("VK_DOWN", { type: "keypress" });
|
||||||
|
synthesizeKey("VK_DOWN", { type: "keypress" });
|
||||||
|
synthesizeKey("VK_DOWN", { type: "keypress" });
|
||||||
|
synthesizeKey("VK_DOWN", { type: "keyup" });
|
||||||
|
is(numberInput, 4, "input event should be dispatched for each up/down arrow key keypress event, even when rapidly repeated");
|
||||||
|
is(number.value, -2, "sanity check value of number control after multiple keydown events");
|
||||||
|
|
||||||
|
number.blur();
|
||||||
|
is(numberInput, 4, "input event shouldn't be dispatched on blur");
|
||||||
|
}
|
||||||
|
|
||||||
MockFilePicker.cleanup();
|
MockFilePicker.cleanup();
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,19 +35,20 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=935501
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SimpleTest.waitForFocus(function() {
|
SimpleTest.waitForFocus(function() {
|
||||||
test();
|
test();
|
||||||
SimpleTest.finish();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function test() {
|
var input = document.getElementById("input");
|
||||||
var input = document.getElementById("input");
|
var inputRect = input.getBoundingClientRect();
|
||||||
var inputRect = input.getBoundingClientRect();
|
|
||||||
|
|
||||||
// Points over the input's spin-up and spin-down buttons (as offsets from the
|
// Points over the input's spin-up and spin-down buttons (as offsets from the
|
||||||
// top-left of the input's bounding client rect):
|
// top-left of the input's bounding client rect):
|
||||||
const SPIN_UP_X = inputRect.width - 3;
|
const SPIN_UP_X = inputRect.width - 3;
|
||||||
const SPIN_UP_Y = 3;
|
const SPIN_UP_Y = 3;
|
||||||
const SPIN_DOWN_X = inputRect.width - 3;
|
const SPIN_DOWN_X = inputRect.width - 3;
|
||||||
const SPIN_DOWN_Y = inputRect.height - 3;
|
const SPIN_DOWN_Y = inputRect.height - 3;
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
input.value = 0;
|
||||||
|
|
||||||
// Test click on spin-up button:
|
// Test click on spin-up button:
|
||||||
synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" });
|
synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" });
|
||||||
|
@ -73,37 +74,110 @@ function test() {
|
||||||
is(input.value, 1, "Test that preventDefault() works for click on spin-down button");
|
is(input.value, 1, "Test that preventDefault() works for click on spin-down button");
|
||||||
input.removeEventListener("mousedown", preventDefault, false);
|
input.removeEventListener("mousedown", preventDefault, false);
|
||||||
|
|
||||||
// XXX TODO
|
// Run the spin tests:
|
||||||
|
runNextSpinTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function runNextSpinTest() {
|
||||||
|
try {
|
||||||
|
var [index, test] = spinTests.next();
|
||||||
|
test();
|
||||||
|
} catch(e) {
|
||||||
|
if (e == StopIteration) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
return; // We're all done
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SETTIMEOUT_DELAY = 500;
|
||||||
|
|
||||||
|
var spinTests = Iterator([
|
||||||
// Test spining when the mouse button is kept depressed on the spin-up
|
// Test spining when the mouse button is kept depressed on the spin-up
|
||||||
// button:
|
// button, then moved over the spin-down button:
|
||||||
|
function() {
|
||||||
|
var inputEventCount = 0;
|
||||||
|
input.value = 0;
|
||||||
|
input.addEventListener("input", function(evt) {
|
||||||
|
++inputEventCount;
|
||||||
|
if (inputEventCount == 3) {
|
||||||
|
ok(input.value, 3, "Testing spin-up button");
|
||||||
|
synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousemove" });
|
||||||
|
} else if (inputEventCount == 6) {
|
||||||
|
ok(input.value, 0, "Testing spin direction is reversed after mouse moves from spin-up button to spin-down button");
|
||||||
|
input.removeEventListener("input", arguments.callee, false);
|
||||||
|
synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" });
|
||||||
|
runNextSpinTest();
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" });
|
||||||
|
},
|
||||||
|
|
||||||
// XXX TODO
|
|
||||||
// Test spining when the mouse button is kept depressed on the spin-down
|
// Test spining when the mouse button is kept depressed on the spin-down
|
||||||
// button:
|
// button, then moved over the spin-up button:
|
||||||
|
function() {
|
||||||
|
var inputEventCount = 0;
|
||||||
|
input.value = 0;
|
||||||
|
input.addEventListener("input", function(evt) {
|
||||||
|
++inputEventCount;
|
||||||
|
if (inputEventCount == 3) {
|
||||||
|
ok(input.value, -3, "Testing spin-down button");
|
||||||
|
synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousemove" });
|
||||||
|
} else if (inputEventCount == 6) {
|
||||||
|
ok(input.value, 0, "Testing spin direction is reversed after mouse moves from spin-down button to spin-up button");
|
||||||
|
input.removeEventListener("input", arguments.callee, false);
|
||||||
|
synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" });
|
||||||
|
runNextSpinTest();
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" });
|
||||||
|
},
|
||||||
|
|
||||||
// XXX TODO
|
|
||||||
// Test spin direction reverses when the mouse button is depressod on the
|
|
||||||
// spin-up button, then moved over the spin-down button once the spin begins:
|
|
||||||
|
|
||||||
// XXX TODO
|
|
||||||
// Test spin direction reverses when the mouse button is depressod on the
|
|
||||||
// spin-down button, then moved over the spin-up button once the spin begins:
|
|
||||||
|
|
||||||
// XXX TODO
|
|
||||||
// Test that the spin is stopped when the mouse button is depressod on the
|
|
||||||
// spin-down button, then moved outside both buttons once the spin starts:
|
|
||||||
|
|
||||||
// XXX TODO
|
|
||||||
// Test that the spin is stopped when the mouse button is depressod on the
|
// Test that the spin is stopped when the mouse button is depressod on the
|
||||||
// spin-up button, then moved outside both buttons once the spin starts:
|
// spin-up button, then moved outside both buttons once the spin starts:
|
||||||
|
function() {
|
||||||
|
var inputEventCount = 0;
|
||||||
|
input.value = 0;
|
||||||
|
input.addEventListener("input", function(evt) {
|
||||||
|
++inputEventCount;
|
||||||
|
if (inputEventCount == 3) {
|
||||||
|
synthesizeMouse(input, -1, -1, { type: "mousemove" });
|
||||||
|
var eventHandler = arguments.callee;
|
||||||
|
setTimeout(function() {
|
||||||
|
ok(input.value, 3, "Testing moving the mouse outside the spin buttons stops the spin");
|
||||||
|
ok(inputEventCount, 3, "Testing moving the mouse outside the spin buttons stops the spin input events");
|
||||||
|
input.removeEventListener("input", eventHandler, false);
|
||||||
|
synthesizeMouse(input, -1, -1, { type: "mouseup" });
|
||||||
|
runNextSpinTest();
|
||||||
|
}, SETTIMEOUT_DELAY);
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" });
|
||||||
|
},
|
||||||
|
|
||||||
// XXX TODO
|
|
||||||
// Test that changing the input type in the middle of a spin cancels the spin:
|
// Test that changing the input type in the middle of a spin cancels the spin:
|
||||||
|
function() {
|
||||||
// XXX TODO
|
var inputEventCount = 0;
|
||||||
// Check that we do not spin when a mousedown occurs outside the spin
|
input.value = 0;
|
||||||
// buttons and then the mouse is moved over the buttons:
|
input.addEventListener("input", function(evt) {
|
||||||
}
|
++inputEventCount;
|
||||||
|
if (inputEventCount == 3) {
|
||||||
|
input.type = "text"
|
||||||
|
var eventHandler = arguments.callee;
|
||||||
|
setTimeout(function() {
|
||||||
|
ok(input.value, 3, "Testing changing input type during a spin stops the spin");
|
||||||
|
ok(inputEventCount, 3, "Testing changing input type during a spin stops the spin input events");
|
||||||
|
input.removeEventListener("input", eventHandler, false);
|
||||||
|
synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" });
|
||||||
|
input.type = "number"; // restore
|
||||||
|
runNextSpinTest();
|
||||||
|
}, SETTIMEOUT_DELAY);
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" });
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче