arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/www/bower_components/angular-material/modules/closure/radioButton/radioButton.js
www/bower_components/angular-material/modules/closure/radioButton/radioButton.jsRaw
  1/*!
  2 * Angular Material Design
  3 * https://github.com/angular/material
  4 * @license MIT
  5 * v1.1.3
  6 */
  7goog.provide('ngmaterial.components.radioButton');
  8goog.require('ngmaterial.core');
  9/**
 10 * @ngdoc module
 11 * @name material.components.radioButton
 12 * @description radioButton module!
 13 */
 14mdRadioGroupDirective['$inject'] = ["$mdUtil", "$mdConstant", "$mdTheming", "$timeout"];
 15mdRadioButtonDirective['$inject'] = ["$mdAria", "$mdUtil", "$mdTheming"];
 16angular.module('material.components.radioButton', [
 17  'material.core'
 18])
 19  .directive('mdRadioGroup', mdRadioGroupDirective)
 20  .directive('mdRadioButton', mdRadioButtonDirective);
 21
 22/**
 23 * @ngdoc directive
 24 * @module material.components.radioButton
 25 * @name mdRadioGroup
 26 *
 27 * @restrict E
 28 *
 29 * @description
 30 * The `<md-radio-group>` directive identifies a grouping
 31 * container for the 1..n grouped radio buttons; specified using nested
 32 * `<md-radio-button>` tags.
 33 *
 34 * As per the [material design spec](http://www.google.com/design/spec/style/color.html#color-ui-color-application)
 35 * the radio button is in the accent color by default. The primary color palette may be used with
 36 * the `md-primary` class.
 37 *
 38 * Note: `<md-radio-group>` and `<md-radio-button>` handle tabindex differently
 39 * than the native `<input type='radio'>` controls. Whereas the native controls
 40 * force the user to tab through all the radio buttons, `<md-radio-group>`
 41 * is focusable, and by default the `<md-radio-button>`s are not.
 42 *
 43 * @param {string} ng-model Assignable angular expression to data-bind to.
 44 * @param {boolean=} md-no-ink Use of attribute indicates flag to disable ink ripple effects.
 45 *
 46 * @usage
 47 * <hljs lang="html">
 48 * <md-radio-group ng-model="selected">
 49 *
 50 *   <md-radio-button
 51 *        ng-repeat="d in colorOptions"
 52 *        ng-value="d.value" aria-label="{{ d.label }}">
 53 *
 54 *          {{ d.label }}
 55 *
 56 *   </md-radio-button>
 57 *
 58 * </md-radio-group>
 59 * </hljs>
 60 *
 61 */
 62function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
 63  RadioGroupController.prototype = createRadioGroupControllerProto();
 64
 65  return {
 66    restrict: 'E',
 67    controller: ['$element', RadioGroupController],
 68    require: ['mdRadioGroup', '?ngModel'],
 69    link: { pre: linkRadioGroup }
 70  };
 71
 72  function linkRadioGroup(scope, element, attr, ctrls) {
 73    element.addClass('_md');     // private md component indicator for styling
 74    $mdTheming(element);
 75
 76    var rgCtrl = ctrls[0];
 77    var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();
 78
 79    rgCtrl.init(ngModelCtrl);
 80
 81    scope.mouseActive = false;
 82
 83    element
 84      .attr({
 85        'role': 'radiogroup',
 86        'tabIndex': element.attr('tabindex') || '0'
 87      })
 88      .on('keydown', keydownListener)
 89      .on('mousedown', function(event) {
 90        scope.mouseActive = true;
 91        $timeout(function() {
 92          scope.mouseActive = false;
 93        }, 100);
 94      })
 95      .on('focus', function() {
 96        if(scope.mouseActive === false) {
 97          rgCtrl.$element.addClass('md-focused');
 98        }
 99      })
100      .on('blur', function() {
101        rgCtrl.$element.removeClass('md-focused');
102      });
103
104    /**
105     *
106     */
107    function setFocus() {
108      if (!element.hasClass('md-focused')) { element.addClass('md-focused'); }
109    }
110
111    /**
112     *
113     */
114    function keydownListener(ev) {
115      var keyCode = ev.which || ev.keyCode;
116
117      // Only listen to events that we originated ourselves
118      // so that we don't trigger on things like arrow keys in
119      // inputs.
120
121      if (keyCode != $mdConstant.KEY_CODE.ENTER &&
122          ev.currentTarget != ev.target) {
123        return;
124      }
125
126      switch (keyCode) {
127        case $mdConstant.KEY_CODE.LEFT_ARROW:
128        case $mdConstant.KEY_CODE.UP_ARROW:
129          ev.preventDefault();
130          rgCtrl.selectPrevious();
131          setFocus();
132          break;
133
134        case $mdConstant.KEY_CODE.RIGHT_ARROW:
135        case $mdConstant.KEY_CODE.DOWN_ARROW:
136          ev.preventDefault();
137          rgCtrl.selectNext();
138          setFocus();
139          break;
140
141        case $mdConstant.KEY_CODE.ENTER:
142          var form = angular.element($mdUtil.getClosest(element[0], 'form'));
143          if (form.length > 0) {
144            form.triggerHandler('submit');
145          }
146          break;
147      }
148
149    }
150  }
151
152  function RadioGroupController($element) {
153    this._radioButtonRenderFns = [];
154    this.$element = $element;
155  }
156
157  function createRadioGroupControllerProto() {
158    return {
159      init: function(ngModelCtrl) {
160        this._ngModelCtrl = ngModelCtrl;
161        this._ngModelCtrl.$render = angular.bind(this, this.render);
162      },
163      add: function(rbRender) {
164        this._radioButtonRenderFns.push(rbRender);
165      },
166      remove: function(rbRender) {
167        var index = this._radioButtonRenderFns.indexOf(rbRender);
168        if (index !== -1) {
169          this._radioButtonRenderFns.splice(index, 1);
170        }
171      },
172      render: function() {
173        this._radioButtonRenderFns.forEach(function(rbRender) {
174          rbRender();
175        });
176      },
177      setViewValue: function(value, eventType) {
178        this._ngModelCtrl.$setViewValue(value, eventType);
179        // update the other radio buttons as well
180        this.render();
181      },
182      getViewValue: function() {
183        return this._ngModelCtrl.$viewValue;
184      },
185      selectNext: function() {
186        return changeSelectedButton(this.$element, 1);
187      },
188      selectPrevious: function() {
189        return changeSelectedButton(this.$element, -1);
190      },
191      setActiveDescendant: function (radioId) {
192        this.$element.attr('aria-activedescendant', radioId);
193      },
194      isDisabled: function() {
195        return this.$element[0].hasAttribute('disabled');
196      }
197    };
198  }
199  /**
200   * Change the radio group's selected button by a given increment.
201   * If no button is selected, select the first button.
202   */
203  function changeSelectedButton(parent, increment) {
204    // Coerce all child radio buttons into an array, then wrap then in an iterator
205    var buttons = $mdUtil.iterator(parent[0].querySelectorAll('md-radio-button'), true);
206
207    if (buttons.count()) {
208      var validate = function (button) {
209        // If disabled, then NOT valid
210        return !angular.element(button).attr("disabled");
211      };
212
213      var selected = parent[0].querySelector('md-radio-button.md-checked');
214      var target = buttons[increment < 0 ? 'previous' : 'next'](selected, validate) || buttons.first();
215
216      // Activate radioButton's click listener (triggerHandler won't create a real click event)
217      angular.element(target).triggerHandler('click');
218    }
219  }
220
221}
222
223/**
224 * @ngdoc directive
225 * @module material.components.radioButton
226 * @name mdRadioButton
227 *
228 * @restrict E
229 *
230 * @description
231 * The `<md-radio-button>`directive is the child directive required to be used within `<md-radio-group>` elements.
232 *
233 * While similar to the `<input type="radio" ng-model="" value="">` directive,
234 * the `<md-radio-button>` directive provides ink effects, ARIA support, and
235 * supports use within named radio groups.
236 *
237 * @param {string} ngModel Assignable angular expression to data-bind to.
238 * @param {string=} ngChange Angular expression to be executed when input changes due to user
239 *    interaction with the input element.
240 * @param {string} ngValue Angular expression which sets the value to which the expression should
241 *    be set when selected.
242 * @param {string} value The value to which the expression should be set when selected.
243 * @param {string=} name Property name of the form under which the control is published.
244 * @param {string=} aria-label Adds label to radio button for accessibility.
245 * Defaults to radio button's text. If no text content is available, a warning will be logged.
246 *
247 * @usage
248 * <hljs lang="html">
249 *
250 * <md-radio-button value="1" aria-label="Label 1">
251 *   Label 1
252 * </md-radio-button>
253 *
254 * <md-radio-button ng-model="color" ng-value="specialValue" aria-label="Green">
255 *   Green
256 * </md-radio-button>
257 *
258 * </hljs>
259 *
260 */
261function mdRadioButtonDirective($mdAria, $mdUtil, $mdTheming) {
262
263  var CHECKED_CSS = 'md-checked';
264
265  return {
266    restrict: 'E',
267    require: '^mdRadioGroup',
268    transclude: true,
269    template: '<div class="md-container" md-ink-ripple md-ink-ripple-checkbox>' +
270                '<div class="md-off"></div>' +
271                '<div class="md-on"></div>' +
272              '</div>' +
273              '<div ng-transclude class="md-label"></div>',
274    link: link
275  };
276
277  function link(scope, element, attr, rgCtrl) {
278    var lastChecked;
279
280    $mdTheming(element);
281    configureAria(element, scope);
282
283    // ngAria overwrites the aria-checked inside a $watch for ngValue.
284    // We should defer the initialization until all the watches have fired.
285    // This can also be fixed by removing the `lastChecked` check, but that'll
286    // cause more DOM manipulation on each digest.
287    if (attr.ngValue) {
288      $mdUtil.nextTick(initialize, false);
289    } else {
290      initialize();
291    }
292
293    /**
294     * Initializes the component.
295     */
296    function initialize() {
297      if (!rgCtrl) {
298        throw 'RadioButton: No RadioGroupController could be found.';
299      }
300
301      rgCtrl.add(render);
302      attr.$observe('value', render);
303
304      element
305        .on('click', listener)
306        .on('$destroy', function() {
307          rgCtrl.remove(render);
308        });
309    }
310
311    /**
312     * On click functionality.
313     */
314    function listener(ev) {
315      if (element[0].hasAttribute('disabled') || rgCtrl.isDisabled()) return;
316
317      scope.$apply(function() {
318        rgCtrl.setViewValue(attr.value, ev && ev.type);
319      });
320    }
321
322    /**
323     *  Add or remove the `.md-checked` class from the RadioButton (and conditionally its parent).
324     *  Update the `aria-activedescendant` attribute.
325     */
326    function render() {
327      var checked = rgCtrl.getViewValue() == attr.value;
328
329      if (checked === lastChecked) return;
330
331      if (element[0].parentNode.nodeName.toLowerCase() !== 'md-radio-group') {
332        // If the radioButton is inside a div, then add class so highlighting will work
333        element.parent().toggleClass(CHECKED_CSS, checked);
334      }
335
336      if (checked) {
337        rgCtrl.setActiveDescendant(element.attr('id'));
338      }
339
340      lastChecked = checked;
341
342      element
343        .attr('aria-checked', checked)
344        .toggleClass(CHECKED_CSS, checked);
345    }
346
347    /**
348     * Inject ARIA-specific attributes appropriate for each radio button
349     */
350    function configureAria(element, scope){
351      element.attr({
352        id: attr.id || 'radio_' + $mdUtil.nextUid(),
353        role: 'radio',
354        'aria-checked': 'false'
355      });
356
357      $mdAria.expectWithText(element, 'aria-label');
358    }
359  }
360}
361
362ngmaterial.components.radioButton = angular.module("material.components.radioButton");