B2G/gaia/apps/settings/js/utils.js
/**
 * This emulates <input type="range"> elements on Gecko until they get
 * supported natively.  To be removed when bug 344618 lands.
 * https://bugzilla.mozilla.org/show_bug.cgi?id=344618
 */
This emulates  elements on Gecko until they get
supported natively.  To be removed when bug 344618 lands.
This emulates elements on Gecko until they get supported natively . To be removed when bug 344618 lands .
function bug344618_polyfill() {
  var range = document.createElement('input');
  range.type = 'range';
  if (range.type == 'range') {
    console.warn("bug344618 has landed, there's some dead code to remove.");
    return; 
  }
  var polyfill = function(input) {
    input.dataset.type = 'range';
    var slider = document.createElement('div');
    var thumb = document.createElement('span');
    var fill = document.createElement('span');
    var label = input.parentNode;
    slider.appendChild(fill);
    slider.appendChild(thumb);
    label.insertBefore(slider, input);
    label.classList.add('bug344618_polyfill');
    var min = parseFloat(input.min);
    var max = parseFloat(input.max);
    var refresh = function refresh() {
      var pos = (input.value - min) / (max - min);
      pos = Math.max(pos, 0);
      pos = Math.min(pos, 1);
      fill.style.width = (100 * pos) + '%';
      thumb.style.left = (100 * pos) + '%';
    };
    var updatePosition = function updatePosition(event) {
      var pointer = event.changedTouches && event.changedTouches[0] ?
                    event.changedTouches[0] :
                    event;
      var rect = slider.getBoundingClientRect();
      var pos = (pointer.clientX - rect.left) / rect.width;
      pos = Math.max(pos, 0);
      pos = Math.min(pos, 1);
      fill.style.width = (100 * pos) + '%';
      thumb.style.left = (100 * pos) + '%';
      input.value = min + pos * (max - min);
    };
    var notify = function notify() {
      var evtObject = document.createEvent('Event');
      evtObject.initEvent('change', true, false);
      input.dispatchEvent(evtObject);
    };
    var isDragging = false;
    var onDragStart = function onDragStart(event) {
      updatePosition(event);
      isDragging = true;
    };
    var onDragMove = function onDragMove(event) {
      if (isDragging) {
        updatePosition(event);
        event.preventDefault();
      }
    };
    var onDragStop = function onDragStop(event) {
      if (isDragging) {
        updatePosition(event);
        notify();
      }
      isDragging = false;
    };
    var onClick = function onClick(event) {
      updatePosition(event);
      notify();
    };
    slider.addEventListener('touchstart', onClick);
    thumb.addEventListener('touchstart', onDragStart);
    label.addEventListener('touchmove', onDragMove);
    label.addEventListener('touchend', onDragStop);
    label.addEventListener('touchcancel', onDragStop);
    input.refresh = refresh;
  };
  var selector = 'label:not(.bug344618_polyfill) > input[type="range"]';
  var ranges = document.querySelectorAll(selector);
  for (var i = 0; i < ranges.length; i++) {
    polyfill(ranges[i]);
  }
}
function bug344618_polyfill ( ) { var range = document . createElement ( 'input' ) ; range . type = 'range' ; if ( range . type == 'range' ) { console . warn ( "bug344618 has landed, there's some dead code to remove." ) ; return ; } var polyfill = function ( input ) { input . dataset . type = 'range' ; var slider = document . createElement ( 'div' ) ; var thumb = document . createElement ( 'span' ) ; var fill = document . createElement ( 'span' ) ; var label = input . parentNode ; slider . appendChild ( fill ) ; slider . appendChild ( thumb ) ; label . insertBefore ( slider , input ) ; label . classList . add ( 'bug344618_polyfill' ) ; var min = parseFloat ( input . min ) ; var max = parseFloat ( input . max ) ; var refresh = function refresh ( ) { var pos = ( input . value - min ) / ( max - min ) ; pos = Math . max ( pos , 0 ) ; pos = Math . min ( pos , 1 ) ; fill . style . width = ( 100 * pos ) + '%' ; thumb . style . left = ( 100 * pos ) + '%' ; } ; var updatePosition = function updatePosition ( event ) { var pointer = event . changedTouches && event . changedTouches [ 0 ] ? event . changedTouches [ 0 ] : event ; var rect = slider . getBoundingClientRect ( ) ; var pos = ( pointer . clientX - rect . left ) / rect . width ; pos = Math . max ( pos , 0 ) ; pos = Math . min ( pos , 1 ) ; fill . style . width = ( 100 * pos ) + '%' ; thumb . style . left = ( 100 * pos ) + '%' ; input . value = min + pos * ( max - min ) ; } ; var notify = function notify ( ) { var evtObject = document . createEvent ( 'Event' ) ; evtObject . initEvent ( 'change' , true , false ) ; input . dispatchEvent ( evtObject ) ; } ; var isDragging = false ; var onDragStart = function onDragStart ( event ) { updatePosition ( event ) ; isDragging = true ; } ; var onDragMove = function onDragMove ( event ) { if ( isDragging ) { updatePosition ( event ) ; event . preventDefault ( ) ; } } ; var onDragStop = function onDragStop ( event ) { if ( isDragging ) { updatePosition ( event ) ; notify ( ) ; } isDragging = false ; } ; var onClick = function onClick ( event ) { updatePosition ( event ) ; notify ( ) ; } ; slider . addEventListener ( 'touchstart' , onClick ) ; thumb . addEventListener ( 'touchstart' , onDragStart ) ; label . addEventListener ( 'touchmove' , onDragMove ) ; label . addEventListener ( 'touchend' , onDragStop ) ; label . addEventListener ( 'touchcancel' , onDragStop ) ; input . refresh = refresh ; } ; var selector = 'label:not(.bug344618_polyfill) > input[type="range"]' ; var ranges = document . querySelectorAll ( selector ) ; for ( var i = 0 ; i < ranges . length ; i ++ ) { polyfill ( ranges [ i ] ) ; } }
This emulates <input type="range"> elements on Gecko until they get
 supported natively.
This emulates <input type = " range " > elements on Gecko until they get supported natively .
// <input type="range"> is already supported, early way out. /**
   * The JS polyfill transforms this:
   *
   *   <label>
   *     <input type="range" value="60" />
   *   </label>
   *
   * into this:
   *
   *   <label class="bug344618_polyfill">
   *     <div>
   *       <span style="width: 60%"></span>
   *       <span style="left: 60%"></span>
   *     </div>
   *     <input type="range" value="60" />
   *   </label>
   *
   * JavaScript-wise, two main differences between this polyfill and the
   * standard implementation:
   *   - the `.type' property equals `text' instead of `range';
   *   - the value is a string, not a float.
   */ // move the throbber to the proper position, according to input.value // move the throbber to the proper position, according to touch events // send a 'change' event // user interaction support // preventDefault prevents vertical scrolling // expose the 'refresh' method on <input> // XXX remember to call it after setting input.value manually... // apply to all input[type="range"] elements