text: /*!
   * AngularJS Material Design
   * https://github.com/angular/material
   * @license MIT
   * v1.1.7
   */
  goog.provide('ngmaterial.components.slider');
  goog.require('ngmaterial.core');
    /**
     * @ngdoc module
     * @name material.components.slider
     */
  SliderDirective['$inject'] = ["$$rAF", "$window", "$mdAria", "$mdUtil", "$mdConstant", "$mdTheming", "$mdGesture", "$parse", "$log", "$timeout"];
    angular.module('material.components.slider', [
      'material.core'
    ])
    .directive('mdSlider', SliderDirective)
    .directive('mdSliderContainer', SliderContainerDirective);
  
  /**
   * @ngdoc directive
   * @name mdSliderContainer
   * @module material.components.slider
   * @restrict E
   * @description
   * The `<md-slider-container>` contains slider with two other elements.
   *
   *
   * @usage
   * <h4>Normal Mode</h4>
   * <hljs lang="html">
   * </hljs>
   */
  function SliderContainerDirective() {
    return {
      controller: function () {},
      compile: function (elem) {
        var slider = elem.find('md-slider');
  
        if (!slider) {
          return;
        }
  
        var vertical = slider.attr('md-vertical');
  
        if (vertical !== undefined) {
          elem.attr('md-vertical', '');
        }
  
        if(!slider.attr('flex')) {
          slider.attr('flex', '');
        }
  
        return function postLink(scope, element, attr, ctrl) {
          element.addClass('_md');     // private md component indicator for styling
  
          // We have to manually stop the $watch on ngDisabled because it exists
          // on the parent scope, and won't be automatically destroyed when
          // the component is destroyed.
          function setDisable(value) {
            element.children().attr('disabled', value);
            element.find('input').attr('disabled', value);
          }
  
          var stopDisabledWatch = angular.noop;
  
          if (attr.disabled) {
            setDisable(true);
          }
          else if (attr.ngDisabled) {
            stopDisabledWatch = scope.$watch(attr.ngDisabled, function (value) {
              setDisable(value);
            });
          }
  
          scope.$on('$destroy', function () {
            stopDisabledWatch();
          });
  
          var initialMaxWidth;
  
          ctrl.fitInputWidthToTextLength = function (length) {
            var input = element[0].querySelector('md-input-container');
  
            if (input) {
              var computedStyle = getComputedStyle(input);
              var minWidth = parseInt(computedStyle.minWidth);
              var padding = parseInt(computedStyle.padding) * 2;
  
              initialMaxWidth = initialMaxWidth || parseInt(computedStyle.maxWidth);
              var newMaxWidth = Math.max(initialMaxWidth, minWidth + padding + (minWidth / 2 * length));
  
              input.style.maxWidth = newMaxWidth + 'px';
            }
          };
        };
      }
    };
  }
  
  /**
   * @ngdoc directive
   * @name mdSlider
   * @module material.components.slider
   * @restrict E
   * @description
   * The `<md-slider>` component allows the user to choose from a range of
   * values.
   *
   * As per the [material design spec](http://www.google.com/design/spec/style/color.html#color-ui-color-application)
   * the slider is in the accent color by default. The primary color palette may be used with
   * the `md-primary` class.
   *
   * It has two modes: 'normal' mode, where the user slides between a wide range
   * of values, and 'discrete' mode, where the user slides between only a few
   * select values.
   *
   * To enable discrete mode, add the `md-discrete` attribute to a slider,
   * and use the `step` attribute to change the distance between
   * values the user is allowed to pick.
   *
   * @usage
   * <h4>Normal Mode</h4>
   * <hljs lang="html">
   * <md-slider ng-model="myValue" min="5" max="500">
   * </md-slider>
   * </hljs>
   * <h4>Discrete Mode</h4>
   * <hljs lang="html">
   * <md-slider md-discrete ng-model="myDiscreteValue" step="10" min="10" max="130">
   * </md-slider>
   * </hljs>
   * <h4>Invert Mode</h4>
   * <hljs lang="html">
   * <md-slider md-invert ng-model="myValue" step="10" min="10" max="130">
   * </md-slider>
   * </hljs>
   *
   * @param {boolean=} md-discrete Whether to enable discrete mode.
   * @param {boolean=} md-invert Whether to enable invert mode.
   * @param {number=} step The distance between values the user is allowed to pick. Default 1.
   * @param {number=} min The minimum value the user is allowed to pick. Default 0.
   * @param {number=} max The maximum value the user is allowed to pick. Default 100.
   * @param {number=} round The amount of numbers after the decimal point, maximum is 6 to prevent scientific notation. Default 3.
   */
  function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdTheming, $mdGesture, $parse, $log, $timeout) {
    return {
      scope: {},
      require: ['?ngModel', '?^mdSliderContainer'],
      template:
        '<div class="md-slider-wrapper">' +
          '<div class="md-slider-content">' +
            '<div class="md-track-container">' +
              '<div class="md-track"></div>' +
              '<div class="md-track md-track-fill"></div>' +
              '<div class="md-track-ticks"></div>' +
            '</div>' +
            '<div class="md-thumb-container">' +
              '<div class="md-thumb"></div>' +
              '<div class="md-focus-thumb"></div>' +
              '<div class="md-focus-ring"></div>' +
              '<div class="md-sign">' +
                '<span class="md-thumb-text"></span>' +
              '</div>' +
              '<div class="md-disabled-thumb"></div>' +
            '</div>' +
          '</div>' +
        '</div>',
      compile: compile
    };
  
    // **********************************************************
    // Private Methods
    // **********************************************************
  
    function compile (tElement, tAttrs) {
      var wrapper = angular.element(tElement[0].getElementsByClassName('md-slider-wrapper'));
  
      var tabIndex = tAttrs.tabindex || 0;
      wrapper.attr('tabindex', tabIndex);
  
      if (tAttrs.disabled || tAttrs.ngDisabled) wrapper.attr('tabindex', -1);
  
      tElement.attr('role', 'slider');
  
      $mdAria.expect(tElement, 'aria-label');
  
      return postLink;
    }
  
    function postLink(scope, element, attr, ctrls) {
      $mdTheming(element);
      var ngModelCtrl = ctrls[0] || {
        // Mock ngModelController if it doesn't exist to give us
        // the minimum functionality needed
        $setViewValue: function(val) {
          this.$viewValue = val;
          this.$viewChangeListeners.forEach(function(cb) { cb(); });
        },
        $parsers: [],
        $formatters: [],
        $viewChangeListeners: []
      };
  
      var containerCtrl = ctrls[1];
      var container = angular.element($mdUtil.getClosest(element, '_md-slider-container', true));
      var isDisabled = attr.ngDisabled ? angular.bind(null, $parse(attr.ngDisabled), scope.$parent) : function () {
            return element[0].hasAttribute('disabled');
          };
  
      var thumb = angular.element(element[0].querySelector('.md-thumb'));
      var thumbText = angular.element(element[0].querySelector('.md-thumb-text'));
      var thumbContainer = thumb.parent();
      var trackContainer = angular.element(element[0].querySelector('.md-track-container'));
      var activeTrack = angular.element(element[0].querySelector('.md-track-fill'));
      var tickContainer = angular.element(element[0].querySelector('.md-track-ticks'));
      var wrapper = angular.element(element[0].getElementsByClassName('md-slider-wrapper'));
      var content = angular.element(element[0].getElementsByClassName('md-slider-content'));
      var throttledRefreshDimensions = $mdUtil.throttle(refreshSliderDimensions, 5000);
  
      // Default values, overridable by attrs
      var DEFAULT_ROUND = 3;
      var vertical = angular.isDefined(attr.mdVertical);
      var discrete = angular.isDefined(attr.mdDiscrete);
      var invert = angular.isDefined(attr.mdInvert);
      angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(0);
      angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(100);
      angular.isDefined(attr.step)? attr.$observe('step', updateStep) : updateStep(1);
      angular.isDefined(attr.round)? attr.$observe('round', updateRound) : updateRound(DEFAULT_ROUND);
  
      // We have to manually stop the $watch on ngDisabled because it exists
      // on the parent scope, and won't be automatically destroyed when
      // the component is destroyed.
      var stopDisabledWatch = angular.noop;
      if (attr.ngDisabled) {
        stopDisabledWatch = scope.$parent.$watch(attr.ngDisabled, updateAriaDisabled);
      }
  
      $mdGesture.register(wrapper, 'drag', { horizontal: !vertical });
  
      scope.mouseActive = false;
  
      wrapper
        .on('keydown', keydownListener)
        .on('mousedown', mouseDownListener)
        .on('focus', focusListener)
        .on('blur', blurListener)
        .on('$md.pressdown', onPressDown)
        .on('$md.pressup', onPressUp)
        .on('$md.dragstart', onDragStart)
        .on('$md.drag', onDrag)
        .on('$md.dragend', onDragEnd);
  
      // On resize, recalculate the slider's dimensions and re-render
      function updateAll() {
        refreshSliderDimensions();
        ngModelRender();
      }
      setTimeout(updateAll, 0);
  
      var debouncedUpdateAll = $$rAF.throttle(updateAll);
      angular.element($window).on('resize', debouncedUpdateAll);
  
      scope.$on('$destroy', function() {
        angular.element($window).off('resize', debouncedUpdateAll);
      });
  
      ngModelCtrl.$render = ngModelRender;
      ngModelCtrl.$viewChangeListeners.push(ngModelRender);
      ngModelCtrl.$formatters.push(minMaxValidator);
      ngModelCtrl.$formatters.push(stepValidator);
  
      /**
       * Attributes
       */
      var min;
      var max;
      var step;
      var round;
      function updateMin(value) {
        min = parseFloat(value);
        element.attr('aria-valuemin', value);
        updateAll();
      }
      function updateMax(value) {
        max = parseFloat(value);
        element.attr('aria-valuemax', value);
        updateAll();
      }
      function updateStep(value) {
        step = parseFloat(value);
      }
      function updateRound(value) {
        // Set max round digits to 6, after 6 the input uses scientific notation
        round = minMaxValidator(parseInt(value), 0, 6);
      }
      function updateAriaDisabled() {
        element.attr('aria-disabled', !!isDisabled());
      }
  
      // Draw the ticks with canvas.
      // The alternative to drawing ticks with canvas is to draw one element for each tick,
      // which could quickly become a performance bottleneck.
      var tickCanvas, tickCtx;
      function redrawTicks() {
        if (!discrete || isDisabled()) return;
        if ( angular.isUndefined(step) )         return;
  
        if ( step <= 0 ) {
          var msg = 'Slider step value must be greater than zero when in discrete mode';
          $log.error(msg);
          throw new Error(msg);
        }
  
        var numSteps = Math.floor( (max - min) / step );
        if (!tickCanvas) {
          tickCanvas = angular.element('<canvas>').css('position', 'absolute');
          tickContainer.append(tickCanvas);
  
          tickCtx = tickCanvas[0].getContext('2d');
        }
  
        var dimensions = getSliderDimensions();
  
        // If `dimensions` doesn't have height and width it might be the first attempt so we will refresh dimensions
        if (dimensions && !dimensions.height && !dimensions.width) {
          refreshSliderDimensions();
          dimensions = sliderDimensions;
        }
  
        tickCanvas[0].width = dimensions.width;
        tickCanvas[0].height = dimensions.height;
  
        var distance;
        for (var i = 0; i <= numSteps; i++) {
          var trackTicksStyle = $window.getComputedStyle(tickContainer[0]);
          tickCtx.fillStyle = trackTicksStyle.color || 'black';
  
          distance = Math.floor((vertical ? dimensions.height : dimensions.width) * (i / numSteps));
  
          tickCtx.fillRect(vertical ? 0 : distance - 1,
            vertical ? distance - 1 : 0,
            vertical ? dimensions.width : 2,
            vertical ? 2 : dimensions.height);
        }
      }
  
      function clearTicks() {
        if(tickCanvas && tickCtx) {
          var dimensions = getSliderDimensions();
          tickCtx.clearRect(0, 0, dimensions.width, dimensions.height);
        }
      }
  
      /**
       * Refreshing Dimensions
       */
      var sliderDimensions = {};
      refreshSliderDimensions();
      function refreshSliderDimensions() {
        sliderDimensions = trackContainer[0].getBoundingClientRect();
      }
      function getSliderDimensions() {
        throttledRefreshDimensions();
        return sliderDimensions;
      }
  
      /**
       * left/right/up/down arrow listener
       */
      function keydownListener(ev) {
        if (isDisabled()) return;
  
        var changeAmount;
        if (vertical ? ev.keyCode === $mdConstant.KEY_CODE.DOWN_ARROW : ev.keyCode === $mdConstant.KEY_CODE.LEFT_ARROW) {
          changeAmount = -step;
        } else if (vertical ? ev.keyCode === $mdConstant.KEY_CODE.UP_ARROW : ev.keyCode === $mdConstant.KEY_CODE.RIGHT_ARROW) {
          changeAmount = step;
        }
        changeAmount = invert ? -changeAmount : changeAmount;
        if (changeAmount) {
          if (ev.metaKey || ev.ctrlKey || ev.altKey) {
            changeAmount *= 4;
          }
          ev.preventDefault();
          ev.stopPropagation();
          scope.$evalAsync(function() {
            setModelValue(ngModelCtrl.$viewValue + changeAmount);
          });
        }
      }
  
      function mouseDownListener() {
        redrawTicks();
  
        scope.mouseActive = true;
        wrapper.removeClass('md-focused');
  
        $timeout(function() {
          scope.mouseActive = false;
        }, 100);
      }
  
      function focusListener() {
        if (scope.mouseActive === false) {
          wrapper.addClass('md-focused');
        }
      }
  
      function blurListener() {
        wrapper.removeClass('md-focused');
        element.removeClass('md-active');
        clearTicks();
      }
  
      /**
       * ngModel setters and validators
       */
      function setModelValue(value) {
        ngModelCtrl.$setViewValue( minMaxValidator(stepValidator(value)) );
      }
      function ngModelRender() {
        if (isNaN(ngModelCtrl.$viewValue)) {
          ngModelCtrl.$viewValue = ngModelCtrl.$modelValue;
        }
  
        ngModelCtrl.$viewValue = minMaxValidator(ngModelCtrl.$viewValue);
  
        var percent = valueToPercent(ngModelCtrl.$viewValue);
        scope.modelValue = ngModelCtrl.$viewValue;
        element.attr('aria-valuenow', ngModelCtrl.$viewValue);
        setSliderPercent(percent);
        thumbText.text( ngModelCtrl.$viewValue );
      }
  
      function minMaxValidator(value, minValue, maxValue) {
        if (angular.isNumber(value)) {
          minValue = angular.isNumber(minValue) ? minValue : min;
          maxValue = angular.isNumber(maxValue) ? maxValue : max;
  
          return Math.max(minValue, Math.min(maxValue, value));
        }
      }
  
      function stepValidator(value) {
        if (angular.isNumber(value)) {
          var formattedValue = (Math.round((value - min) / step) * step + min);
          formattedValue = (Math.round(formattedValue * Math.pow(10, round)) / Math.pow(10, round));
  
          if (containerCtrl && containerCtrl.fitInputWidthToTextLength){
            $mdUtil.debounce(function () {
              containerCtrl.fitInputWidthToTextLength(formattedValue.toString().length);
            }, 100)();
          }
  
          return formattedValue;
        }
      }
  
      /**
       * @param percent 0-1
       */
      function setSliderPercent(percent) {
  
        percent = clamp(percent);
  
        var thumbPosition = (percent * 100) + '%';
        var activeTrackPercent = invert ? (1 - percent) * 100 + '%' : thumbPosition;
  
        if (vertical) {
          thumbContainer.css('bottom', thumbPosition);
        }
        else {
          $mdUtil.bidiProperty(thumbContainer, 'left', 'right', thumbPosition);
        }
  
        
        activeTrack.css(vertical ? 'height' : 'width', activeTrackPercent);
  
        element.toggleClass((invert ? 'md-max' : 'md-min'), percent === 0);
        element.toggleClass((invert ? 'md-min' : 'md-max'), percent === 1);
      }
  
      /**
       * Slide listeners
       */
      var isDragging = false;
  
      function onPressDown(ev) {
        if (isDisabled()) return;
  
        element.addClass('md-active');
        element[0].focus();
        refreshSliderDimensions();
  
        var exactVal = percentToValue( positionToPercent( vertical ? ev.pointer.y : ev.pointer.x ));
        var closestVal = minMaxValidator( stepValidator(exactVal) );
        scope.$apply(function() {
          setModelValue( closestVal );
          setSliderPercent( valueToPercent(closestVal));
        });
      }
      function onPressUp(ev) {
        if (isDisabled()) return;
  
        element.removeClass('md-dragging');
  
        var exactVal = percentToValue( positionToPercent( vertical ? ev.pointer.y : ev.pointer.x ));
        var closestVal = minMaxValidator( stepValidator(exactVal) );
        scope.$apply(function() {
          setModelValue(closestVal);
          ngModelRender();
        });
      }
      function onDragStart(ev) {
        if (isDisabled()) return;
        isDragging = true;
  
        ev.stopPropagation();
  
        element.addClass('md-dragging');
        setSliderFromEvent(ev);
      }
      function onDrag(ev) {
        if (!isDragging) return;
        ev.stopPropagation();
        setSliderFromEvent(ev);
      }
      function onDragEnd(ev) {
        if (!isDragging) return;
        ev.stopPropagation();
        isDragging = false;
      }
  
      function setSliderFromEvent(ev) {
        // While panning discrete, update only the
        // visual positioning but not the model value.
        if ( discrete ) adjustThumbPosition( vertical ? ev.pointer.y : ev.pointer.x );
        else            doSlide( vertical ? ev.pointer.y : ev.pointer.x );
      }
  
      /**
       * Slide the UI by changing the model value
       * @param x
       */
      function doSlide( x ) {
        scope.$evalAsync( function() {
          setModelValue( percentToValue( positionToPercent(x) ));
        });
      }
  
      /**
       * Slide the UI without changing the model (while dragging/panning)
       * @param x
       */
      function adjustThumbPosition( x ) {
        var exactVal = percentToValue( positionToPercent( x ));
        var closestVal = minMaxValidator( stepValidator(exactVal) );
        setSliderPercent( positionToPercent(x) );
        thumbText.text( closestVal );
      }
  
      /**
      * Clamps the value to be between 0 and 1.
      * @param {number} value The value to clamp.
      * @returns {number}
      */
      function clamp(value) {
        return Math.max(0, Math.min(value || 0, 1));
      }
  
      /**
       * Convert position on slider to percentage value of offset from beginning...
       * @param position
       * @returns {number}
       */
      function positionToPercent( position ) {
        var offset = vertical ? sliderDimensions.top : sliderDimensions.left;
        var size = vertical ? sliderDimensions.height : sliderDimensions.width;
        var calc = (position - offset) / size;
  
        if (!vertical && $mdUtil.bidi() === 'rtl') {
          calc = 1 - calc;
        }
  
        return Math.max(0, Math.min(1, vertical ? 1 - calc : calc));
      }
  
      /**
       * Convert percentage offset on slide to equivalent model value
       * @param percent
       * @returns {*}
       */
      function percentToValue( percent ) {
        var adjustedPercent = invert ? (1 - percent) : percent;
        return (min + adjustedPercent * (max - min));
      }
  
      function valueToPercent( val ) {
        var percent = (val - min) / (max - min);
        return invert ? (1 - percent) : percent;
      }
    }
  }
  
  ngmaterial.components.slider = angular.module("material.components.slider");