socketioMEANseed/www/bower_components/angular-aria/angular-aria.js
www/bower_components/angular-aria/angular-aria.jsRaw
1/**
2 * @license AngularJS v1.6.1
3 * (c) 2010-2016 Google, Inc. http://angularjs.org
4 * License: MIT
5 */
6(function(window, angular) {'use strict';
7
8/**
9 * @ngdoc module
10 * @name ngAria
11 * @description
12 *
13 * The `ngAria` module provides support for common
14 * [<abbr title="Accessible Rich Internet Applications">ARIA</abbr>](http://www.w3.org/TR/wai-aria/)
15 * attributes that convey state or semantic information about the application for users
16 * of assistive technologies, such as screen readers.
17 *
18 * <div doc-module-components="ngAria"></div>
19 *
20 * ## Usage
21 *
22 * For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following
23 * directives are supported:
24 * `ngModel`, `ngChecked`, `ngReadonly`, `ngRequired`, `ngValue`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`,
25 * `ngDblClick`, and `ngMessages`.
26 *
27 * Below is a more detailed breakdown of the attributes handled by ngAria:
28 *
29 * | Directive | Supported Attributes |
30 * |---------------------------------------------|-----------------------------------------------------------------------------------------------------|
31 * | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required, input roles |
32 * | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled |
33 * | {@link ng.directive:ngRequired ngRequired} | aria-required |
34 * | {@link ng.directive:ngChecked ngChecked} | aria-checked |
35 * | {@link ng.directive:ngReadonly ngReadonly} | aria-readonly |
36 * | {@link ng.directive:ngValue ngValue} | aria-checked |
37 * | {@link ng.directive:ngShow ngShow} | aria-hidden |
38 * | {@link ng.directive:ngHide ngHide} | aria-hidden |
39 * | {@link ng.directive:ngDblclick ngDblclick} | tabindex |
40 * | {@link module:ngMessages ngMessages} | aria-live |
41 * | {@link ng.directive:ngClick ngClick} | tabindex, keydown event, button role |
42 *
43 * Find out more information about each directive by reading the
44 * {@link guide/accessibility ngAria Developer Guide}.
45 *
46 * ## Example
47 * Using ngDisabled with ngAria:
48 * ```html
49 * <md-checkbox ng-disabled="disabled">
50 * ```
51 * Becomes:
52 * ```html
53 * <md-checkbox ng-disabled="disabled" aria-disabled="true">
54 * ```
55 *
56 * ## Disabling Attributes
57 * It's possible to disable individual attributes added by ngAria with the
58 * {@link ngAria.$ariaProvider#config config} method. For more details, see the
59 * {@link guide/accessibility Developer Guide}.
60 */
61var ngAriaModule = angular.module('ngAria', ['ng']).
62 provider('$aria', $AriaProvider);
63
64/**
65* Internal Utilities
66*/
67var nodeBlackList = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'DETAILS', 'SUMMARY'];
68
69var isNodeOneOf = function(elem, nodeTypeArray) {
70 if (nodeTypeArray.indexOf(elem[0].nodeName) !== -1) {
71 return true;
72 }
73};
74/**
75 * @ngdoc provider
76 * @name $ariaProvider
77 * @this
78 *
79 * @description
80 *
81 * Used for configuring the ARIA attributes injected and managed by ngAria.
82 *
83 * ```js
84 * angular.module('myApp', ['ngAria'], function config($ariaProvider) {
85 * $ariaProvider.config({
86 * ariaValue: true,
87 * tabindex: false
88 * });
89 * });
90 *```
91 *
92 * ## Dependencies
93 * Requires the {@link ngAria} module to be installed.
94 *
95 */
96function $AriaProvider() {
97 var config = {
98 ariaHidden: true,
99 ariaChecked: true,
100 ariaReadonly: true,
101 ariaDisabled: true,
102 ariaRequired: true,
103 ariaInvalid: true,
104 ariaValue: true,
105 tabindex: true,
106 bindKeydown: true,
107 bindRoleForClick: true
108 };
109
110 /**
111 * @ngdoc method
112 * @name $ariaProvider#config
113 *
114 * @param {object} config object to enable/disable specific ARIA attributes
115 *
116 * - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags
117 * - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags
118 * - **ariaReadonly** – `{boolean}` – Enables/disables aria-readonly tags
119 * - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags
120 * - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags
121 * - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid tags
122 * - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and
123 * aria-valuenow tags
124 * - **tabindex** – `{boolean}` – Enables/disables tabindex tags
125 * - **bindKeydown** – `{boolean}` – Enables/disables keyboard event binding on non-interactive
126 * elements (such as `div` or `li`) using ng-click, making them more accessible to users of
127 * assistive technologies
128 * - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements (such as
129 * `div` or `li`) using ng-click, making them more accessible to users of assistive
130 * technologies
131 *
132 * @description
133 * Enables/disables various ARIA attributes
134 */
135 this.config = function(newConfig) {
136 config = angular.extend(config, newConfig);
137 };
138
139 function watchExpr(attrName, ariaAttr, nodeBlackList, negate) {
140 return function(scope, elem, attr) {
141 var ariaCamelName = attr.$normalize(ariaAttr);
142 if (config[ariaCamelName] && !isNodeOneOf(elem, nodeBlackList) && !attr[ariaCamelName]) {
143 scope.$watch(attr[attrName], function(boolVal) {
144 // ensure boolean value
145 boolVal = negate ? !boolVal : !!boolVal;
146 elem.attr(ariaAttr, boolVal);
147 });
148 }
149 };
150 }
151 /**
152 * @ngdoc service
153 * @name $aria
154 *
155 * @description
156 * @priority 200
157 *
158 * The $aria service contains helper methods for applying common
159 * [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.
160 *
161 * ngAria injects common accessibility attributes that tell assistive technologies when HTML
162 * elements are enabled, selected, hidden, and more. To see how this is performed with ngAria,
163 * let's review a code snippet from ngAria itself:
164 *
165 *```js
166 * ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
167 * return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
168 * }])
169 *```
170 * Shown above, the ngAria module creates a directive with the same signature as the
171 * traditional `ng-disabled` directive. But this ngAria version is dedicated to
172 * solely managing accessibility attributes on custom elements. The internal `$aria` service is
173 * used to watch the boolean attribute `ngDisabled`. If it has not been explicitly set by the
174 * developer, `aria-disabled` is injected as an attribute with its value synchronized to the
175 * value in `ngDisabled`.
176 *
177 * Because ngAria hooks into the `ng-disabled` directive, developers do not have to do
178 * anything to enable this feature. The `aria-disabled` attribute is automatically managed
179 * simply as a silent side-effect of using `ng-disabled` with the ngAria module.
180 *
181 * The full list of directives that interface with ngAria:
182 * * **ngModel**
183 * * **ngChecked**
184 * * **ngReadonly**
185 * * **ngRequired**
186 * * **ngDisabled**
187 * * **ngValue**
188 * * **ngShow**
189 * * **ngHide**
190 * * **ngClick**
191 * * **ngDblclick**
192 * * **ngMessages**
193 *
194 * Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each
195 * directive.
196 *
197 *
198 * ## Dependencies
199 * Requires the {@link ngAria} module to be installed.
200 */
201 this.$get = function() {
202 return {
203 config: function(key) {
204 return config[key];
205 },
206 $$watchExpr: watchExpr
207 };
208 };
209}
210
211
212ngAriaModule.directive('ngShow', ['$aria', function($aria) {
213 return $aria.$$watchExpr('ngShow', 'aria-hidden', [], true);
214}])
215.directive('ngHide', ['$aria', function($aria) {
216 return $aria.$$watchExpr('ngHide', 'aria-hidden', [], false);
217}])
218.directive('ngValue', ['$aria', function($aria) {
219 return $aria.$$watchExpr('ngValue', 'aria-checked', nodeBlackList, false);
220}])
221.directive('ngChecked', ['$aria', function($aria) {
222 return $aria.$$watchExpr('ngChecked', 'aria-checked', nodeBlackList, false);
223}])
224.directive('ngReadonly', ['$aria', function($aria) {
225 return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nodeBlackList, false);
226}])
227.directive('ngRequired', ['$aria', function($aria) {
228 return $aria.$$watchExpr('ngRequired', 'aria-required', nodeBlackList, false);
229}])
230.directive('ngModel', ['$aria', function($aria) {
231
232 function shouldAttachAttr(attr, normalizedAttr, elem, allowBlacklistEls) {
233 return $aria.config(normalizedAttr) && !elem.attr(attr) && (allowBlacklistEls || !isNodeOneOf(elem, nodeBlackList));
234 }
235
236 function shouldAttachRole(role, elem) {
237 // if element does not have role attribute
238 // AND element type is equal to role (if custom element has a type equaling shape) <-- remove?
239 // AND element is not in nodeBlackList
240 return !elem.attr('role') && (elem.attr('type') === role) && !isNodeOneOf(elem, nodeBlackList);
241 }
242
243 function getShape(attr, elem) {
244 var type = attr.type,
245 role = attr.role;
246
247 return ((type || role) === 'checkbox' || role === 'menuitemcheckbox') ? 'checkbox' :
248 ((type || role) === 'radio' || role === 'menuitemradio') ? 'radio' :
249 (type === 'range' || role === 'progressbar' || role === 'slider') ? 'range' : '';
250 }
251
252 return {
253 restrict: 'A',
254 require: 'ngModel',
255 priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
256 compile: function(elem, attr) {
257 var shape = getShape(attr, elem);
258
259 return {
260 post: function(scope, elem, attr, ngModel) {
261 var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem, false);
262
263 function ngAriaWatchModelValue() {
264 return ngModel.$modelValue;
265 }
266
267 function getRadioReaction(newVal) {
268 // Strict comparison would cause a BC
269 // eslint-disable-next-line eqeqeq
270 var boolVal = (attr.value == ngModel.$viewValue);
271 elem.attr('aria-checked', boolVal);
272 }
273
274 function getCheckboxReaction() {
275 elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
276 }
277
278 switch (shape) {
279 case 'radio':
280 case 'checkbox':
281 if (shouldAttachRole(shape, elem)) {
282 elem.attr('role', shape);
283 }
284 if (shouldAttachAttr('aria-checked', 'ariaChecked', elem, false)) {
285 scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
286 getRadioReaction : getCheckboxReaction);
287 }
288 if (needsTabIndex) {
289 elem.attr('tabindex', 0);
290 }
291 break;
292 case 'range':
293 if (shouldAttachRole(shape, elem)) {
294 elem.attr('role', 'slider');
295 }
296 if ($aria.config('ariaValue')) {
297 var needsAriaValuemin = !elem.attr('aria-valuemin') &&
298 (attr.hasOwnProperty('min') || attr.hasOwnProperty('ngMin'));
299 var needsAriaValuemax = !elem.attr('aria-valuemax') &&
300 (attr.hasOwnProperty('max') || attr.hasOwnProperty('ngMax'));
301 var needsAriaValuenow = !elem.attr('aria-valuenow');
302
303 if (needsAriaValuemin) {
304 attr.$observe('min', function ngAriaValueMinReaction(newVal) {
305 elem.attr('aria-valuemin', newVal);
306 });
307 }
308 if (needsAriaValuemax) {
309 attr.$observe('max', function ngAriaValueMinReaction(newVal) {
310 elem.attr('aria-valuemax', newVal);
311 });
312 }
313 if (needsAriaValuenow) {
314 scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) {
315 elem.attr('aria-valuenow', newVal);
316 });
317 }
318 }
319 if (needsTabIndex) {
320 elem.attr('tabindex', 0);
321 }
322 break;
323 }
324
325 if (!attr.hasOwnProperty('ngRequired') && ngModel.$validators.required
326 && shouldAttachAttr('aria-required', 'ariaRequired', elem, false)) {
327 // ngModel.$error.required is undefined on custom controls
328 attr.$observe('required', function() {
329 elem.attr('aria-required', !!attr['required']);
330 });
331 }
332
333 if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem, true)) {
334 scope.$watch(function ngAriaInvalidWatch() {
335 return ngModel.$invalid;
336 }, function ngAriaInvalidReaction(newVal) {
337 elem.attr('aria-invalid', !!newVal);
338 });
339 }
340 }
341 };
342 }
343 };
344}])
345.directive('ngDisabled', ['$aria', function($aria) {
346 return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
347}])
348.directive('ngMessages', function() {
349 return {
350 restrict: 'A',
351 require: '?ngMessages',
352 link: function(scope, elem, attr, ngMessages) {
353 if (!elem.attr('aria-live')) {
354 elem.attr('aria-live', 'assertive');
355 }
356 }
357 };
358})
359.directive('ngClick',['$aria', '$parse', function($aria, $parse) {
360 return {
361 restrict: 'A',
362 compile: function(elem, attr) {
363 var fn = $parse(attr.ngClick, /* interceptorFn */ null, /* expensiveChecks */ true);
364 return function(scope, elem, attr) {
365
366 if (!isNodeOneOf(elem, nodeBlackList)) {
367
368 if ($aria.config('bindRoleForClick') && !elem.attr('role')) {
369 elem.attr('role', 'button');
370 }
371
372 if ($aria.config('tabindex') && !elem.attr('tabindex')) {
373 elem.attr('tabindex', 0);
374 }
375
376 if ($aria.config('bindKeydown') && !attr.ngKeydown && !attr.ngKeypress && !attr.ngKeyup) {
377 elem.on('keydown', function(event) {
378 var keyCode = event.which || event.keyCode;
379 if (keyCode === 32 || keyCode === 13) {
380 scope.$apply(callback);
381 }
382
383 function callback() {
384 fn(scope, { $event: event });
385 }
386 });
387 }
388 }
389 };
390 }
391 };
392}])
393.directive('ngDblclick', ['$aria', function($aria) {
394 return function(scope, elem, attr) {
395 if ($aria.config('tabindex') && !elem.attr('tabindex') && !isNodeOneOf(elem, nodeBlackList)) {
396 elem.attr('tabindex', 0);
397 }
398 };
399}]);
400
401
402})(window, window.angular);