Code and Stuff

Jan 17, 2013

HTML5 Range Input Hack (Firefox)

UPDATE: Firefox 23 added support for the input range

Firefox does not implement the input type range yet. So here's a quick hack that creates a scrollbar for them. The code is implemented using JQuery. I'm sure there are plugins for JQuery that do this, but wanted to try my idea.

WARNING: Did not test it much and the range input needs all attributes (min, max, step)

The idea is pretty simple. For each input element with type range do the following:

  1. Create a div of same size as the input and set its overflow attribute to scroll
  2. Add a horizontally bigger element to this div
  3. Add a scroll event listener to the div that will:
    1. Compute the percentual of scroll
    2. Scale that to the min, max and step values of the input range
    3. Set the range value to the scale value
    4. inform the input it changed
  4. Make the input invisible by setting its opacity to 0 and position it somewhere far away (left:-5000, top:-5000). Do NOT set the display value to none!
function makeRange(dummy, element) {
  if ($.browser.mozilla) {
    var width = $(element).width();

    var minimum = +$(element).attr("min");
    var maximum = +$(element).attr("max");
    var step = $(element).attr("step");
    var size = maximum - minimum;
    var value = $(element).val();

    // 1 and 2
    var newDiv = $('<div style="overflow:scroll; display:inline-block;width:' + width + 'px; height:15px;">\
                    <div style="height:0px;width:' + (width * 4) + 'px">&nbsp;</div></div>');
    newDiv.insertBefore($(element));

    // scroll to initial value
    newDiv.scrollLeft(width * 3 *((value - minimum) / size));
    
    // 3
    newDiv.scroll(function(e){

      // 3.1
      var width = $(this).children().first().width() - $(this).width();
      var value = this.scrollLeft / width;

      // 3.2
      var size = maximum - minimum;
      var fval = minimum + size * value;
      var ival = Math.floor(fval / step) * step;
      ival = ival.toFixed(Math.ceil(Math.abs(Math.log(step))));
      
      // 3.3
      $(element).val(ival);
      
      // 3.4
      $(element).trigger('change');
    });

    // 4
    $(element).css("position","absolute");
    $(element).css("opacity","0");
    $(element).css("left", "-5000px");
    $(element).css("top", "-5000px");
  }
}

// call this when the Document is loaded
$(function(){
    // for each input element of type range 
    $("input[type=range]").each(makeRange);
});
If this method is used in a page where ranges are create dynamically in javascript, make sure to run it only on the newly created range. Otherwise you will end up with duplicate scrollbars on existing ranges.

No comments: