4579e0aa35026c7aa8ed632b621fb28c92859b64
[vnfsdk/refrepo.git] /
1 /*!
2  * Angular Material Design
3  * https://github.com/angular/material
4  * @license MIT
5  * v1.1.3
6  */
7 (function( window, angular, undefined ){
8 "use strict";
9
10 /**
11  * @ngdoc module
12  * @name material.components.checkbox
13  * @description Checkbox module!
14  */
15 MdCheckboxDirective['$inject'] = ["inputDirective", "$mdAria", "$mdConstant", "$mdTheming", "$mdUtil", "$mdInteraction"];
16 angular
17   .module('material.components.checkbox', ['material.core'])
18   .directive('mdCheckbox', MdCheckboxDirective);
19
20 /**
21  * @ngdoc directive
22  * @name mdCheckbox
23  * @module material.components.checkbox
24  * @restrict E
25  *
26  * @description
27  * The checkbox directive is used like the normal [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).
28  *
29  * As per the [material design spec](http://www.google.com/design/spec/style/color.html#color-color-schemes)
30  * the checkbox is in the accent color by default. The primary color palette may be used with
31  * the `md-primary` class.
32  *
33  * @param {string} ng-model Assignable angular expression to data-bind to.
34  * @param {string=} name Property name of the form under which the control is published.
35  * @param {expression=} ng-true-value The value to which the expression should be set when selected.
36  * @param {expression=} ng-false-value The value to which the expression should be set when not selected.
37  * @param {string=} ng-change Angular expression to be executed when input changes due to user interaction with the input element.
38  * @param {boolean=} md-no-ink Use of attribute indicates use of ripple ink effects
39  * @param {string=} aria-label Adds label to checkbox for accessibility.
40  *     Defaults to checkbox's text. If no default text is found, a warning will be logged.
41  * @param {expression=} md-indeterminate This determines when the checkbox should be rendered as 'indeterminate'.
42  *     If a truthy expression or no value is passed in the checkbox renders in the md-indeterminate state.
43  *     If falsy expression is passed in it just looks like a normal unchecked checkbox.
44  *     The indeterminate, checked, and unchecked states are mutually exclusive. A box cannot be in any two states at the same time.
45  *     Adding the 'md-indeterminate' attribute overrides any checked/unchecked rendering logic.
46  *     When using the 'md-indeterminate' attribute use 'ng-checked' to define rendering logic instead of using 'ng-model'.
47  * @param {expression=} ng-checked If this expression evaluates as truthy, the 'md-checked' css class is added to the checkbox and it
48  *     will appear checked.
49  *
50  * @usage
51  * <hljs lang="html">
52  * <md-checkbox ng-model="isChecked" aria-label="Finished?">
53  *   Finished ?
54  * </md-checkbox>
55  *
56  * <md-checkbox md-no-ink ng-model="hasInk" aria-label="No Ink Effects">
57  *   No Ink Effects
58  * </md-checkbox>
59  *
60  * <md-checkbox ng-disabled="true" ng-model="isDisabled" aria-label="Disabled">
61  *   Disabled
62  * </md-checkbox>
63  *
64  * </hljs>
65  *
66  */
67 function MdCheckboxDirective(inputDirective, $mdAria, $mdConstant, $mdTheming, $mdUtil, $mdInteraction) {
68   inputDirective = inputDirective[0];
69
70   return {
71     restrict: 'E',
72     transclude: true,
73     require: ['^?mdInputContainer', '?ngModel', '?^form'],
74     priority: $mdConstant.BEFORE_NG_ARIA,
75     template:
76       '<div class="md-container" md-ink-ripple md-ink-ripple-checkbox>' +
77         '<div class="md-icon"></div>' +
78       '</div>' +
79       '<div ng-transclude class="md-label"></div>',
80     compile: compile
81   };
82
83   // **********************************************************
84   // Private Methods
85   // **********************************************************
86
87   function compile (tElement, tAttrs) {
88     tAttrs.$set('tabindex', tAttrs.tabindex || '0');
89     tAttrs.$set('type', 'checkbox');
90     tAttrs.$set('role', tAttrs.type);
91
92     return  {
93       pre: function(scope, element) {
94         // Attach a click handler during preLink, in order to immediately stop propagation
95         // (especially for ng-click) when the checkbox is disabled.
96         element.on('click', function(e) {
97           if (this.hasAttribute('disabled')) {
98             e.stopImmediatePropagation();
99           }
100         });
101       },
102       post: postLink
103     };
104
105     function postLink(scope, element, attr, ctrls) {
106       var isIndeterminate;
107       var containerCtrl = ctrls[0];
108       var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();
109       var formCtrl = ctrls[2];
110
111       if (containerCtrl) {
112         var isErrorGetter = containerCtrl.isErrorGetter || function() {
113           return ngModelCtrl.$invalid && (ngModelCtrl.$touched || (formCtrl && formCtrl.$submitted));
114         };
115
116         containerCtrl.input = element;
117
118         scope.$watch(isErrorGetter, containerCtrl.setInvalid);
119       }
120
121       $mdTheming(element);
122
123       // Redirect focus events to the root element, because IE11 is always focusing the container element instead
124       // of the md-checkbox element. This causes issues when using ngModelOptions: `updateOnBlur`
125       element.children().on('focus', function() {
126         element.focus();
127       });
128
129       if ($mdUtil.parseAttributeBoolean(attr.mdIndeterminate)) {
130         setIndeterminateState();
131         scope.$watch(attr.mdIndeterminate, setIndeterminateState);
132       }
133
134       if (attr.ngChecked) {
135         scope.$watch(scope.$eval.bind(scope, attr.ngChecked), function(value) {
136           ngModelCtrl.$setViewValue(value);
137           ngModelCtrl.$render();
138         });
139       }
140
141       $$watchExpr('ngDisabled', 'tabindex', {
142         true: '-1',
143         false: attr.tabindex
144       });
145
146       $mdAria.expectWithText(element, 'aria-label');
147
148       // Reuse the original input[type=checkbox] directive from Angular core.
149       // This is a bit hacky as we need our own event listener and own render
150       // function.
151       inputDirective.link.pre(scope, {
152         on: angular.noop,
153         0: {}
154       }, attr, [ngModelCtrl]);
155
156       element.on('click', listener)
157         .on('keypress', keypressHandler)
158         .on('focus', function() {
159           if ($mdInteraction.getLastInteractionType() === 'keyboard') {
160             element.addClass('md-focused');
161           }
162         })
163         .on('blur', function() {
164           element.removeClass('md-focused');
165         });
166
167       ngModelCtrl.$render = render;
168
169       function $$watchExpr(expr, htmlAttr, valueOpts) {
170         if (attr[expr]) {
171           scope.$watch(attr[expr], function(val) {
172             if (valueOpts[val]) {
173               element.attr(htmlAttr, valueOpts[val]);
174             }
175           });
176         }
177       }
178
179       function keypressHandler(ev) {
180         var keyCode = ev.which || ev.keyCode;
181         if (keyCode === $mdConstant.KEY_CODE.SPACE || keyCode === $mdConstant.KEY_CODE.ENTER) {
182           ev.preventDefault();
183           element.addClass('md-focused');
184           listener(ev);
185         }
186       }
187
188       function listener(ev) {
189         // skipToggle boolean is used by the switch directive to prevent the click event
190         // when releasing the drag. There will be always a click if releasing the drag over the checkbox
191         if (element[0].hasAttribute('disabled') || scope.skipToggle) {
192           return;
193         }
194
195         scope.$apply(function() {
196           // Toggle the checkbox value...
197           var viewValue = attr.ngChecked ? attr.checked : !ngModelCtrl.$viewValue;
198
199           ngModelCtrl.$setViewValue(viewValue, ev && ev.type);
200           ngModelCtrl.$render();
201         });
202       }
203
204       function render() {
205         // Cast the $viewValue to a boolean since it could be undefined
206         element.toggleClass('md-checked', !!ngModelCtrl.$viewValue && !isIndeterminate);
207       }
208
209       function setIndeterminateState(newValue) {
210         isIndeterminate = newValue !== false;
211         if (isIndeterminate) {
212           element.attr('aria-checked', 'mixed');
213         }
214         element.toggleClass('md-indeterminate', isIndeterminate);
215       }
216     }
217   }
218 }
219
220 })(window, window.angular);