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