function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
  RadioGroupController.prototype = createRadioGroupControllerProto();

  return {
    restrict: 'E',
    controller: ['$element', RadioGroupController],
    require: ['mdRadioGroup', '?ngModel'],
    link: { pre: linkRadioGroup }
  };

  function linkRadioGroup(scope, element, attr, ctrls) {
    element.addClass('_md');     // private md component indicator for styling
    $mdTheming(element);

    var rgCtrl = ctrls[0];
    var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();

    rgCtrl.init(ngModelCtrl);

    scope.mouseActive = false;

    element
      .attr({
        'role': 'radiogroup',
        'tabIndex': element.attr('tabindex') || '0'
      })
      .on('keydown', keydownListener)
      .on('mousedown', function(event) {
        scope.mouseActive = true;
        $timeout(function() {
          scope.mouseActive = false;
        }, 100);
      })
      .on('focus', function() {
        if (scope.mouseActive === false) {
          rgCtrl.$element.addClass('md-focused');
        }
      })
      .on('blur', function() {
        rgCtrl.$element.removeClass('md-focused');
      });

    /**
     *
     */
    function setFocus() {
      if (!element.hasClass('md-focused')) { element.addClass('md-focused'); }
    }

    /**
     *
     */
    function keydownListener(ev) {
      var keyCode = ev.which || ev.keyCode;

      // Only listen to events that we originated ourselves
      // so that we don't trigger on things like arrow keys in
      // inputs.

      if (keyCode != $mdConstant.KEY_CODE.ENTER &&
          ev.currentTarget != ev.target) {
        return;
      }

      switch (keyCode) {
        case $mdConstant.KEY_CODE.LEFT_ARROW:
        case $mdConstant.KEY_CODE.UP_ARROW:
          ev.preventDefault();
          rgCtrl.selectPrevious();
          setFocus();
          break;

        case $mdConstant.KEY_CODE.RIGHT_ARROW:
        case $mdConstant.KEY_CODE.DOWN_ARROW:
          ev.preventDefault();
          rgCtrl.selectNext();
          setFocus();
          break;

        case $mdConstant.KEY_CODE.ENTER:
          var form = angular.element($mdUtil.getClosest(element[0], 'form'));
          if (form.length > 0) {
            form.triggerHandler('submit');
          }
          break;
      }

    }
  }

  function RadioGroupController($element) {
    this._radioButtonRenderFns = [];
    this.$element = $element;
  }

  function createRadioGroupControllerProto() {
    return {
      init: function(ngModelCtrl) {
        this._ngModelCtrl = ngModelCtrl;
        this._ngModelCtrl.$render = angular.bind(this, this.render);
      },
      add: function(rbRender) {
        this._radioButtonRenderFns.push(rbRender);
      },
      remove: function(rbRender) {
        var index = this._radioButtonRenderFns.indexOf(rbRender);
        if (index !== -1) {
          this._radioButtonRenderFns.splice(index, 1);
        }
      },
      render: function() {
        this._radioButtonRenderFns.forEach(function(rbRender) {
          rbRender();
        });
      },
      setViewValue: function(value, eventType) {
        this._ngModelCtrl.$setViewValue(value, eventType);
        // update the other radio buttons as well
        this.render();
      },
      getViewValue: function() {
        return this._ngModelCtrl.$viewValue;
      },
      selectNext: function() {
        return changeSelectedButton(this.$element, 1);
      },
      selectPrevious: function() {
        return changeSelectedButton(this.$element, -1);
      },
      setActiveDescendant: function (radioId) {
        this.$element.attr('aria-activedescendant', radioId);
      },
      isDisabled: function() {
        return this.$element[0].hasAttribute('disabled');
      }
    };
  }
  /**
   * Change the radio group's selected button by a given increment.
   * If no button is selected, select the first button.
   */
  function changeSelectedButton(parent, increment) {
    // Coerce all child radio buttons into an array, then wrap then in an iterator
    var buttons = $mdUtil.iterator(parent[0].querySelectorAll('md-radio-button'), true);

    if (buttons.count()) {
      var validate = function (button) {
        // If disabled, then NOT valid
        return !angular.element(button).attr("disabled");
      };

      var selected = parent[0].querySelector('md-radio-button.md-checked');
      var target = buttons[increment < 0 ? 'previous' : 'next'](selected, validate) || buttons.first();

      // Activate radioButton's click listener (triggerHandler won't create a real click event)
      angular.element(target).triggerHandler('click');
    }
  }

}
function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
  RadioGroupController.prototype = createRadioGroupControllerProto();

  return {
    restrict: 'E',
    controller: ['$element', RadioGroupController],
    require: ['mdRadioGroup', '?ngModel'],
    link: { pre: linkRadioGroup }
  };

  function linkRadioGroup(scope, element, attr, ctrls) {
    element.addClass('_md');     // private md component indicator for styling
    $mdTheming(element);

    var rgCtrl = ctrls[0];
    var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();

    rgCtrl.init(ngModelCtrl);

    scope.mouseActive = false;

    element
      .attr({
        'role': 'radiogroup',
        'tabIndex': element.attr('tabindex') || '0'
      })
      .on('keydown', keydownListener)
      .on('mousedown', function(event) {
        scope.mouseActive = true;
        $timeout(function() {
          scope.mouseActive = false;
        }, 100);
      })
      .on('focus', function() {
        if (scope.mouseActive === false) {
          rgCtrl.$element.addClass('md-focused');
        }
      })
      .on('blur', function() {
        rgCtrl.$element.removeClass('md-focused');
      });

    /**
     *
     */
    function setFocus() {
      if (!element.hasClass('md-focused')) { element.addClass('md-focused'); }
    }

    /**
     *
     */
    function keydownListener(ev) {
      var keyCode = ev.which || ev.keyCode;

      // Only listen to events that we originated ourselves
      // so that we don't trigger on things like arrow keys in
      // inputs.

      if (keyCode != $mdConstant.KEY_CODE.ENTER &&
          ev.currentTarget != ev.target) {
        return;
      }

      switch (keyCode) {
        case $mdConstant.KEY_CODE.LEFT_ARROW:
        case $mdConstant.KEY_CODE.UP_ARROW:
          ev.preventDefault();
          rgCtrl.selectPrevious();
          setFocus();
          break;

        case $mdConstant.KEY_CODE.RIGHT_ARROW:
        case $mdConstant.KEY_CODE.DOWN_ARROW:
          ev.preventDefault();
          rgCtrl.selectNext();
          setFocus();
          break;

        case $mdConstant.KEY_CODE.ENTER:
          var form = angular.element($mdUtil.getClosest(element[0], 'form'));
          if (form.length > 0) {
            form.triggerHandler('submit');
          }
          break;
      }

    }
  }

  function RadioGroupController($element) {
    this._radioButtonRenderFns = [];
    this.$element = $element;
  }

  function createRadioGroupControllerProto() {
    return {
      init: function(ngModelCtrl) {
        this._ngModelCtrl = ngModelCtrl;
        this._ngModelCtrl.$render = angular.bind(this, this.render);
      },
      add: function(rbRender) {
        this._radioButtonRenderFns.push(rbRender);
      },
      remove: function(rbRender) {
        var index = this._radioButtonRenderFns.indexOf(rbRender);
        if (index !== -1) {
          this._radioButtonRenderFns.splice(index, 1);
        }
      },
      render: function() {
        this._radioButtonRenderFns.forEach(function(rbRender) {
          rbRender();
        });
      },
      setViewValue: function(value, eventType) {
        this._ngModelCtrl.$setViewValue(value, eventType);
        // update the other radio buttons as well
        this.render();
      },
      getViewValue: function() {
        return this._ngModelCtrl.$viewValue;
      },
      selectNext: function() {
        return changeSelectedButton(this.$element, 1);
      },
      selectPrevious: function() {
        return changeSelectedButton(this.$element, -1);
      },
      setActiveDescendant: function (radioId) {
        this.$element.attr('aria-activedescendant', radioId);
      },
      isDisabled: function() {
        return this.$element[0].hasAttribute('disabled');
      }
    };
  }
  /**
   * Change the radio group's selected button by a given increment.
   * If no button is selected, select the first button.
   */
  function changeSelectedButton(parent, increment) {
    // Coerce all child radio buttons into an array, then wrap then in an iterator
    var buttons = $mdUtil.iterator(parent[0].querySelectorAll('md-radio-button'), true);

    if (buttons.count()) {
      var validate = function (button) {
        // If disabled, then NOT valid
        return !angular.element(button).attr("disabled");
      };

      var selected = parent[0].querySelector('md-radio-button.md-checked');
      var target = buttons[increment < 0 ? 'previous' : 'next'](selected, validate) || buttons.first();

      // Activate radioButton's click listener (triggerHandler won't create a real click event)
      angular.element(target).triggerHandler('click');
    }
  }

}
function mdRadioGroupDirective ( $mdUtil , $mdConstant , $mdTheming , $timeout ) { RadioGroupController . prototype = createRadioGroupControllerProto ( ) ; return { restrict : 'E' , controller : [ '$element' , RadioGroupController ] , require : [ 'mdRadioGroup' , '?ngModel' ] , link : { pre : linkRadioGroup } } ; function linkRadioGroup ( scope , element , attr , ctrls ) { element . addClass ( '_md' ) ; // private md component indicator for styling $mdTheming ( element ) ; var rgCtrl = ctrls [ 0 ] ; var ngModelCtrl = ctrls [ 1 ] || $mdUtil . fakeNgModel ( ) ; rgCtrl . init ( ngModelCtrl ) ; scope . mouseActive = false ; element . attr ( { 'role' : 'radiogroup' , 'tabIndex' : element . attr ( 'tabindex' ) || '0' } ) . on ( 'keydown' , keydownListener ) . on ( 'mousedown' , function ( event ) { scope . mouseActive = true ; $timeout ( function ( ) { scope . mouseActive = false ; } , 100 ) ; } ) . on ( 'focus' , function ( ) { if ( scope . mouseActive === false ) { rgCtrl . $element . addClass ( 'md-focused' ) ; } } ) . on ( 'blur' , function ( ) { rgCtrl . $element . removeClass ( 'md-focused' ) ; } ) ; /**
     *
     */ function setFocus ( ) { if ( ! element . hasClass ( 'md-focused' ) ) { element . addClass ( 'md-focused' ) ; } } /**
     *
     */ function keydownListener ( ev ) { var keyCode = ev . which || ev . keyCode ; // Only listen to events that we originated ourselves // so that we don't trigger on things like arrow keys in // inputs. if ( keyCode != $mdConstant . KEY_CODE . ENTER && ev . currentTarget != ev . target ) { return ; } switch ( keyCode ) { case $mdConstant . KEY_CODE . LEFT_ARROW : case $mdConstant . KEY_CODE . UP_ARROW : ev . preventDefault ( ) ; rgCtrl . selectPrevious ( ) ; setFocus ( ) ; break ; case $mdConstant . KEY_CODE . RIGHT_ARROW : case $mdConstant . KEY_CODE . DOWN_ARROW : ev . preventDefault ( ) ; rgCtrl . selectNext ( ) ; setFocus ( ) ; break ; case $mdConstant . KEY_CODE . ENTER : var form = angular . element ( $mdUtil . getClosest ( element [ 0 ] , 'form' ) ) ; if ( form . length > 0 ) { form . triggerHandler ( 'submit' ) ; } break ; } } } function RadioGroupController ( $element ) { this . _radioButtonRenderFns = [ ] ; this . $element = $element ; } function createRadioGroupControllerProto ( ) { return { init : function ( ngModelCtrl ) { this . _ngModelCtrl = ngModelCtrl ; this . _ngModelCtrl . $render = angular . bind ( this , this . render ) ; } , add : function ( rbRender ) { this . _radioButtonRenderFns . push ( rbRender ) ; } , remove : function ( rbRender ) { var index = this . _radioButtonRenderFns . indexOf ( rbRender ) ; if ( index !== - 1 ) { this . _radioButtonRenderFns . splice ( index , 1 ) ; } } , render : function ( ) { this . _radioButtonRenderFns . forEach ( function ( rbRender ) { rbRender ( ) ; } ) ; } , setViewValue : function ( value , eventType ) { this . _ngModelCtrl . $setViewValue ( value , eventType ) ; // update the other radio buttons as well this . render ( ) ; } , getViewValue : function ( ) { return this . _ngModelCtrl . $viewValue ; } , selectNext : function ( ) { return changeSelectedButton ( this . $element , 1 ) ; } , selectPrevious : function ( ) { return changeSelectedButton ( this . $element , - 1 ) ; } , setActiveDescendant : function ( radioId ) { this . $element . attr ( 'aria-activedescendant' , radioId ) ; } , isDisabled : function ( ) { return this . $element [ 0 ] . hasAttribute ( 'disabled' ) ; } } ; } /**
   * Change the radio group's selected button by a given increment.
   * If no button is selected, select the first button.
   */ function changeSelectedButton ( parent , increment ) { // Coerce all child radio buttons into an array, then wrap then in an iterator var buttons = $mdUtil . iterator ( parent [ 0 ] . querySelectorAll ( 'md-radio-button' ) , true ) ; if ( buttons . count ( ) ) { var validate = function ( button ) { // If disabled, then NOT valid return ! angular . element ( button ) . attr ( "disabled" ) ; } ; var selected = parent [ 0 ] . querySelector ( 'md-radio-button.md-checked' ) ; var target = buttons [ increment < 0 ? 'previous' : 'next' ] ( selected , validate ) || buttons . first ( ) ; // Activate radioButton's click listener (triggerHandler won't create a real click event) angular . element ( target ) . triggerHandler ( 'click' ) ; } } }
@ngdoc directive
@module material.components.radioButton
@name mdRadioGroup

@restrict E

@description
The `<md-radio-group>` directive identifies a grouping
container for the 1..n grouped radio buttons; specified using nested
`<md-radio-button>` elements.

The radio button uses the accent color by default. The primary color palette may be used with
the `md-primary` class.

Note: `<md-radio-group>` and `<md-radio-button>` handle `tabindex` differently
than the native `<input type="radio">` controls. Whereas the native controls
force the user to tab through all the radio buttons, `<md-radio-group>`
is focusable and by default the `<md-radio-button>`s are not.

@param {string} ng-model Assignable angular expression to data-bind to.
@param {string=} ng-change AngularJS expression to be executed when input changes due to user
interaction.
@param {boolean=} md-no-ink If present, disables ink ripple effects.

@usage
<hljs lang="html">
<md-radio-group ng-model="selected">
<md-radio-button ng-repeat="item in items"
ng-value="item.value" aria-label="{{item.label}}">
{{ item.label }}
</md-radio-button>
</md-radio-group>
</hljs>
@ngdoc directive @module material . components . radioButton @name mdRadioGroup
Directive for RadioGroup