Reputation: 36028
I want to make a spinner controll in my page,I tried it like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Simple spinner</title>
<script type="text/javascript">
function RotateSpinner(spinnerId, up) {
var ele=document.getElementById(spinnerId);
ele.value=parseInt(ele.value)+up;
var t=setTimeout(function(){
if(window.rotate_start)
RotateSpinner(spinnerId,up);
else
clearTimeout(t);
},500);
}
</script>
<style>
*
{
padding: 0;
margin: 0;
}
.spinner
{
list-style: none;
display: inline-block;
line-height: 0;
vertical-align: middle;
}
.spinner input
{
font-size: .45em;
border-width: .5px;
height: 1.5em;
width: 2em;
}
</style>
</head>
<body>
<input id="spinner" type="text" value="0" />
<ul class="spinner">
<li>
<input type="button" value="▲" onmousedown="window.rotate_start=true;RotateSpinner('spinner', 1)" onmouseup="window.rotate_start=false;"/>
</li>
<li>
<input type="button" value="▼" onmousedown="window.rotate_start=true;RotateSpinner('spinner', -1)" onmouseup="window.rotate_start=false;"/>
</li>
</ul>
</body>
</html>
However,it does not work as what I want, when I click the "up" button,I want the value only add once,but sometime it will add the value many times.
Can anyone have a check and fix it?
Here is the live example
Upvotes: 0
Views: 1703
Reputation: 121
Using an interval shortens and simplifies the code a lot. (tested on IE9, Chrome21, FF14) I used http://jsfiddle.net/KmMCE/3/ for testing but I haven't updated the sample though.
Markup:
<input id="spinner" type="text" value="0" />
<input type="button" value="▲"
onmousedown="spinnerMouseDown('spinner', 1);"
onmouseup="stopSpinner();" onmouseout="stopSpinner();" />
<input type="button" value="▼"
onmousedown="spinnerMouseDown('spinner', -1);"
onmouseup="stopSpinner();" onmouseout="stopSpinner();" />
JavaScript:
function spinnerMouseDown(id, value) {
var el = document.getElementById(id);
window.spinnerTimer = window.setInterval(function(){
el.value = parseInt(el.value) + value;
}, 100);
}
function stopSpinner() {
window.clearInterval(window.spinnerTimer);
}
Upvotes: 2
Reputation: 27880
There are two main problems here:
Management of the onmouseup
and onmousedown
events.
You can get an onmousedown
in a button, and if the onmouseup
is outside the button, window.rotate_start
will still be true
. onmouseup
and onmousedown
alone are not enough to accomplish what you want.
Address this by using a global onmouseup
and onmousedown
event handler that will track the state in a variable. Keep other variables to check for onmouseover
and onmouseout
on the buttons to know wheter to update the value or not and how (+1/-1).
Timeouts running when doing single clicks accumulate. This is what's causing the effect described in the question. Use a variable that'll hold if the timeout is set, and clear the timeout when the onmousedown
and onmouseover
for a button are set (i.e. when a single click is made, forget about all pending timer executions).
See an example in this fiddle: http://jsfiddle.net/KmMCE/3/
<input type="button" value="▲"
onmouseover="window.upfocus = 1;" onmouseout="window.upfocus = 0;" />
<input type="button" value="▼"
onmouseover="window.downfocus = 1;" onmouseout="window.downfocus = 0;" />
var timingOut = false;
var upfocus = 0;
var downfocus = 0;
var mouseDown = 0;
document.body.onmousedown = function() {
mouseDown = 1;
if (window.upfocus == 1) {
if (timingOut) {
clearTimeout(t);
timingOut = false;
}
RotateSpinner('spinner', 1);
}
else if (window.downfocus == 1) {
if (timingOut) {
clearTimeout(t);
timingOut = false;
}
RotateSpinner('spinner', -1);
}
}
document.body.onmouseup = function() {
mouseDown = 0;
}
function RotateSpinner(spinnerId, up) {
var ele = document.getElementById(spinnerId);
ele.value = parseInt(ele.value) + up;
timingOut = true;
t = setTimeout(function() {
if (mouseDown == 1 && up == 1 && window.upfocus == 1) {
RotateSpinner(spinnerId, up);
}
else if (mouseDown == 1 && up == -1 && window.downfocus == 1) {
RotateSpinner(spinnerId, up);
}
else {
clearTimeout(t);
timingOut = false;
}
}, 500);
}
Upvotes: 1