source: trip-planner-front/node_modules/angular-material/modules/js/checkbox/checkbox.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*!
2 * AngularJS Material Design
3 * https://github.com/angular/material
4 * @license MIT
5 * v1.2.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 */
15MdCheckboxDirective['$inject'] = ["inputDirective", "$mdAria", "$mdConstant", "$mdTheming", "$mdUtil", "$mdInteraction"];
16angular
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
28 * [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).
29 *
30 * As per the [Material Design spec](https://material.io/archive/guidelines/style/color.html#color-color-palette)
31 * the checkbox is in the accent color by default. The primary color palette may be used with
32 * the `md-primary` class.
33 *
34 * @param {expression} ng-model Assignable angular expression to data-bind to.
35 * @param {string=} name Property name of the form under which the control is published.
36 * @param {expression=} ng-true-value The value to which the expression should be set when selected.
37 * @param {expression=} ng-false-value The value to which the expression should be set when not
38 * selected.
39 * @param {expression=} ng-change Expression to be executed when the model value changes.
40 * @param {boolean=} md-no-ink If present, disable ink ripple effects.
41 * @param {string=} aria-label Adds label to checkbox for accessibility.
42 * Defaults to checkbox's text. If no default text is found, a warning will be logged.
43 * @param {expression=} md-indeterminate This determines when the checkbox should be rendered as
44 * 'indeterminate'. If a truthy expression or no value is passed in the checkbox renders in the
45 * md-indeterminate state. If falsy expression is passed in it just looks like a normal unchecked
46 * checkbox. The indeterminate, checked, and unchecked states are mutually exclusive. A box
47 * cannot be in any two states at the same time. Adding the 'md-indeterminate' attribute
48 * overrides any checked/unchecked rendering logic. When using the 'md-indeterminate' attribute
49 * use 'ng-checked' to define rendering logic instead of using 'ng-model'.
50 * @param {expression=} ng-checked If this expression evaluates as truthy, the 'md-checked' css
51 * class is added to the checkbox and it will appear checked.
52 *
53 * @usage
54 * <hljs lang="html">
55 * <md-checkbox ng-model="isChecked" aria-label="Finished?">
56 * Finished ?
57 * </md-checkbox>
58 *
59 * <md-checkbox md-no-ink ng-model="hasInk" aria-label="No Ink Effects">
60 * No Ink Effects
61 * </md-checkbox>
62 *
63 * <md-checkbox ng-disabled="true" ng-model="isDisabled" aria-label="Disabled">
64 * Disabled
65 * </md-checkbox>
66 *
67 * </hljs>
68 *
69 */
70function MdCheckboxDirective(inputDirective, $mdAria, $mdConstant, $mdTheming, $mdUtil, $mdInteraction) {
71 inputDirective = inputDirective[0];
72
73 return {
74 restrict: 'E',
75 transclude: true,
76 require: ['^?mdInputContainer', '?ngModel', '?^form'],
77 priority: $mdConstant.BEFORE_NG_ARIA,
78 template:
79 '<div class="md-container" md-ink-ripple md-ink-ripple-checkbox>' +
80 '<div class="md-icon"></div>' +
81 '</div>' +
82 '<div ng-transclude class="md-label"></div>',
83 compile: compile
84 };
85
86 // **********************************************************
87 // Private Methods
88 // **********************************************************
89
90 function compile (tElement, tAttrs) {
91 tAttrs.$set('tabindex', tAttrs.tabindex || '0');
92 tAttrs.$set('type', 'checkbox');
93 tAttrs.$set('role', tAttrs.type);
94 tElement.addClass('md-auto-horizontal-margin');
95
96 return {
97 pre: function(scope, element) {
98 // Attach a click handler during preLink, in order to immediately stop propagation
99 // (especially for ng-click) when the checkbox is disabled.
100 element.on('click', function(e) {
101 if (this.hasAttribute('disabled')) {
102 e.stopImmediatePropagation();
103 }
104 });
105 },
106 post: postLink
107 };
108
109 function postLink(scope, element, attr, ctrls) {
110 var isIndeterminate;
111 var containerCtrl = ctrls[0];
112 var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();
113 var formCtrl = ctrls[2];
114 var labelHasLink = element.find('a').length > 0;
115
116 // The original component structure is not accessible when the checkbox's label contains a link.
117 // In order to keep backwards compatibility, we're only changing the structure of the component
118 // when we detect a link within the label. Using a span after the md-checkbox and attaching it
119 // via aria-labelledby allows screen readers to find and work with the link within the label.
120 if (labelHasLink) {
121 var labelId = 'label-' + $mdUtil.nextUid();
122 attr.$set('aria-labelledby', labelId);
123
124 var label = element.children()[1];
125 // Use jQLite here since ChildNode.remove() is not supported in IE11.
126 angular.element(label).remove();
127 label.removeAttribute('ng-transclude');
128 label.className = 'md-checkbox-link-label';
129 label.setAttribute('id', labelId);
130 element.after(label);
131 // Make sure that clicking on the label still causes the checkbox to be toggled, when appropriate.
132 var externalLabel = element.next();
133 externalLabel.on('click', listener);
134 }
135
136 if (containerCtrl) {
137 var isErrorGetter = containerCtrl.isErrorGetter || function() {
138 return ngModelCtrl.$invalid && (ngModelCtrl.$touched || (formCtrl && formCtrl.$submitted));
139 };
140
141 containerCtrl.input = element;
142
143 scope.$watch(isErrorGetter, containerCtrl.setInvalid);
144 }
145
146 $mdTheming(element);
147
148 // Redirect focus events to the root element, because IE11 is always focusing the container element instead
149 // of the md-checkbox element. This causes issues when using ngModelOptions: `updateOnBlur`
150 element.children().on('focus', function() {
151 element.focus();
152 });
153
154 if ($mdUtil.parseAttributeBoolean(attr.mdIndeterminate)) {
155 setIndeterminateState();
156 scope.$watch(attr.mdIndeterminate, setIndeterminateState);
157 }
158
159 if (attr.ngChecked) {
160 scope.$watch(scope.$eval.bind(scope, attr.ngChecked), function(value) {
161 ngModelCtrl.$setViewValue(value);
162 ngModelCtrl.$render();
163 });
164 }
165
166 $$watchExpr('ngDisabled', 'tabindex', {
167 true: '-1',
168 false: attr.tabindex
169 });
170
171 // Don't emit a warning when the label has a link within it. In that case we'll use
172 // aria-labelledby to point to another span that should be read as the label.
173 if (!labelHasLink) {
174 $mdAria.expectWithText(element, 'aria-label');
175 }
176
177 // Reuse the original input[type=checkbox] directive from AngularJS core.
178 // This is a bit hacky as we need our own event listener and own render
179 // function.
180 inputDirective.link.pre(scope, {
181 on: angular.noop,
182 0: {}
183 }, attr, [ngModelCtrl]);
184
185 element.on('click', listener)
186 .on('keypress', keypressHandler)
187 .on('focus', function() {
188 if ($mdInteraction.getLastInteractionType() === 'keyboard') {
189 element.addClass('md-focused');
190 }
191 })
192 .on('blur', function() {
193 element.removeClass('md-focused');
194 });
195
196 ngModelCtrl.$render = render;
197
198 function $$watchExpr(expr, htmlAttr, valueOpts) {
199 if (attr[expr]) {
200 scope.$watch(attr[expr], function(val) {
201 if (valueOpts[val]) {
202 element.attr(htmlAttr, valueOpts[val]);
203 }
204 });
205 }
206 }
207
208 /**
209 * @param {KeyboardEvent} ev 'keypress' event to handle
210 */
211 function keypressHandler(ev) {
212 var keyCode = ev.which || ev.keyCode;
213 var submit, form;
214
215 ev.preventDefault();
216 switch (keyCode) {
217 case $mdConstant.KEY_CODE.SPACE:
218 element.addClass('md-focused');
219 listener(ev);
220 break;
221 case $mdConstant.KEY_CODE.ENTER:
222 // Match the behavior of the native <input type="checkbox">.
223 // When the enter key is pressed while focusing a native checkbox inside a form,
224 // the browser will trigger a `click` on the first non-disabled submit button/input
225 // in the form. Note that this is different from text inputs, which
226 // will directly submit the form without needing a submit button/input to be present.
227 form = $mdUtil.getClosest(ev.target, 'form');
228 if (form) {
229 submit = form.querySelector('button[type="submit"]:enabled, input[type="submit"]:enabled');
230 if (submit) {
231 submit.click();
232 }
233 }
234 break;
235 }
236 }
237
238 function listener(ev) {
239 // skipToggle boolean is used by the switch directive to prevent the click event
240 // when releasing the drag. There will be always a click if releasing the drag over the checkbox.
241 // If the click came from a link in the checkbox, don't toggle the value.
242 // We want the link to be opened without changing the value in this case.
243 if (element[0].hasAttribute('disabled') || scope.skipToggle || ev.target.tagName === 'A') {
244 return;
245 }
246
247 scope.$apply(function() {
248 // Toggle the checkbox value...
249 var viewValue = attr.ngChecked && attr.ngClick ? attr.checked : !ngModelCtrl.$viewValue;
250
251 ngModelCtrl.$setViewValue(viewValue, ev && ev.type);
252 ngModelCtrl.$render();
253 });
254 }
255
256 function render() {
257 // Cast the $viewValue to a boolean since it could be undefined
258 var checked = !!ngModelCtrl.$viewValue && !isIndeterminate;
259 element.toggleClass('md-checked', checked);
260 if (!isIndeterminate) {
261 if (checked) {
262 element.attr('aria-checked', 'true');
263 } else {
264 element.attr('aria-checked', 'false');
265 }
266 }
267 }
268
269 /**
270 * @param {string=} newValue
271 */
272 function setIndeterminateState(newValue) {
273 isIndeterminate = newValue !== false;
274 if (isIndeterminate) {
275 element.attr('aria-checked', 'mixed');
276 }
277 element.toggleClass('md-indeterminate', isIndeterminate);
278 ngModelCtrl.$render();
279 }
280 }
281 }
282}
283
284})(window, window.angular);
Note: See TracBrowser for help on using the repository browser.