Input with arbitrary step amount

Use this input to help users quickly enter / select a value respecting an arbitrary step amount.

by DaveAlger

HTML

<input id="bid" placeholder="Enter Bid..."></input><span id="bid_msg">select a valid bid</span><span id="bid_step">in 17€ increments</span>

<div id="options"></div>

CSS

*{ font-family: sans-serif; }
#bid { border: 1px solid #999; padding: 4px; width: 75px; }
#bid.error { color: #a44; border: 1px solid #a44; background-color: #fcc; }
#bid_step { color: #777; font-size: 14px; margin: 0 5px;}
#bid_msg { color: #777; font-size: 14px; display: none; margin-left: 5px;}
#bid_msg.error, #bid_step.error { color: #a44; display: inline-block; font-weight: bold; }
#options { margin-top: 0; padding-top: 0; font-size: 12px; }
#options a, span.current {
  position: relative;
  top: -6px;
  padding-left: 4px;
    color: #06c;
}
span.current { color: #444; }

#options:before {
  content:'\27A5';
  font-size: 28px;
  line-height: 24px;
  color: #aaa;
  margin: 0 5px;
}

#options.error:before {
  color: #a44;
}

JavaScript

var jump = 17;
var bid = 0;
var min_valid = jump;
var options_to_show = 5;

function updateOptions() {
  h = '';
  if (isNumber(bid)) {
    for (var i = 1; i<options_to_show+1; i++) {
      var v = parseInt(bid);
      
      if (v<jump) {
        v = 0;
      }
      else if (v>=jump) {
        v-=jump;
        if (v>=jump) {
          v-=jump;
        }
      }
      
      if (v%jump !== 0) {
        v -= v%jump;
      }
      
      v = v + (i*jump);
      if (i===1) {min_valid = v;}
        if (parseInt(bid)===v) {
            h += '<span class="current">'+v+'€</span> &nbsp; ';
        }
        else {
      h += '<a href="#" class="quicklink" data-valid_option="'+v+'">'+v+'€</a> &nbsp; ';
        }
    }
  }
  else {
    for (var i = 1; i<options_to_show+1; i++) {
      var v = jump*i;
      if (i===1) {min_valid = v;}
      h += '<a href="#" class="quicklink" data-valid_option="'+v+'">'+v+'€</a> &nbsp; ';
    }
  }
  $("#options").html(h);
    $('.quicklink').click(function(){
        up($(this).data('valid_option'));
    });
}

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

function up(v) {
  $("#bid").val(v);
  validate(10);
  $('#bid').keyup();
}

function validate(t) {
  setTimeout(function() { 
    if ($('#bid').val()%jump === 0) {
 $('#bid,#bid_msg,#bid_step,#options').removeClass('error');
    }
    else {
       $('#bid,#bid_msg,#bid_step,#options').addClass('error');
    }
  }, t);
}

$(document).ready(function () {
  $("#jump_amt").html(jump);
  $("#bid").keyup(function() {
    bid = $(this).val();
    updateOptions();
  });
  $("#bid").blur(function() { 
    validate(100);
  });
  $("#bid").focus(function() {
      $('#bid,#bid_msg,#bid_step,#options').removeClass('error');
  });
  updateOptions();
});