feat(ngAria): add support for aria-readonly based on ngReadonly
Closes #14140 Closes #14077
This commit is contained in:
committed by
Martin Staffa
parent
eee2ef6e9d
commit
ae0a716000
@@ -28,12 +28,13 @@ added it as a dependency, you can test a few things:
|
||||
* Fire up a screen reader such as VoiceOver or NVDA to check for ARIA support.
|
||||
[Helpful screen reader tips.](http://webaim.org/articles/screenreader_testing/)
|
||||
|
||||
##Supported directives
|
||||
## Supported directives
|
||||
Currently, ngAria interfaces with the following directives:
|
||||
|
||||
* {@link guide/accessibility#ngmodel ngModel}
|
||||
* {@link guide/accessibility#ngdisabled ngDisabled}
|
||||
* {@link guide/accessibility#ngrequired ngRequired}
|
||||
* {@link guide/accessibility#ngreadonly ngReadonly}
|
||||
* {@link guide/accessibility#ngvaluechecked ngChecked}
|
||||
* {@link guide/accessibility#ngvaluechecked ngValue}
|
||||
* {@link guide/accessibility#ngshow ngShow}
|
||||
@@ -57,6 +58,7 @@ attributes (if they have not been explicitly specified by the developer):
|
||||
* aria-valuenow
|
||||
* aria-invalid
|
||||
* aria-required
|
||||
* aria-readonly
|
||||
|
||||
###Example
|
||||
|
||||
@@ -203,6 +205,25 @@ Becomes:
|
||||
<md-checkbox ng-required="val" aria-required="true"></md-checkbox>
|
||||
```
|
||||
|
||||
<h2 id="ngreadonly">ngReadonly</h2>
|
||||
|
||||
The boolean `readonly` attribute is only valid for native form controls such as `input` and
|
||||
`textarea`. To properly indicate custom element directives such as `<md-checkbox>` or `<custom-input>`
|
||||
as required, using ngAria with {@link ng.ngReadonly ngReadonly} will also add
|
||||
`aria-readonly`. This tells accessibility APIs when a custom control is read-only.
|
||||
|
||||
###Example
|
||||
|
||||
```html
|
||||
<md-checkbox ng-readonly="val"></md-checkbox>
|
||||
```
|
||||
|
||||
Becomes:
|
||||
|
||||
```html
|
||||
<md-checkbox ng-readonly="val" aria-readonly="true"></md-checkbox>
|
||||
```
|
||||
|
||||
<h2 id="ngshow">ngShow</h2>
|
||||
|
||||
>The {@link ng.ngShow ngShow} directive shows or hides the
|
||||
|
||||
+10
-3
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following
|
||||
* directives are supported:
|
||||
* `ngModel`, `ngChecked`, `ngRequired`, `ngValue`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`,
|
||||
* `ngModel`, `ngChecked`, `ngReadonly`, `ngRequired`, `ngValue`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`,
|
||||
* `ngDblClick`, and `ngMessages`.
|
||||
*
|
||||
* Below is a more detailed breakdown of the attributes handled by ngAria:
|
||||
@@ -25,8 +25,9 @@
|
||||
* |---------------------------------------------|----------------------------------------------------------------------------------------|
|
||||
* | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required, input roles |
|
||||
* | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled |
|
||||
* | {@link ng.directive:ngRequired ngRequired} | aria-required |
|
||||
* | {@link ng.directive:ngChecked ngChecked} | aria-checked |
|
||||
* | {@link ng.directive:ngRequired ngRequired} | aria-required
|
||||
* | {@link ng.directive:ngChecked ngChecked} | aria-checked
|
||||
* | {@link ng.directive:ngReadonly ngReadonly} | aria-readonly ||
|
||||
* | {@link ng.directive:ngValue ngValue} | aria-checked |
|
||||
* | {@link ng.directive:ngShow ngShow} | aria-hidden |
|
||||
* | {@link ng.directive:ngHide ngHide} | aria-hidden |
|
||||
@@ -91,6 +92,7 @@ function $AriaProvider() {
|
||||
var config = {
|
||||
ariaHidden: true,
|
||||
ariaChecked: true,
|
||||
ariaReadonly: true,
|
||||
ariaDisabled: true,
|
||||
ariaRequired: true,
|
||||
ariaInvalid: true,
|
||||
@@ -108,6 +110,7 @@ function $AriaProvider() {
|
||||
*
|
||||
* - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags
|
||||
* - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags
|
||||
* - **ariaReadonly** – `{boolean}` – Enables/disables aria-readonly tags
|
||||
* - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags
|
||||
* - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags
|
||||
* - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid tags
|
||||
@@ -170,6 +173,7 @@ function $AriaProvider() {
|
||||
* The full list of directives that interface with ngAria:
|
||||
* * **ngModel**
|
||||
* * **ngChecked**
|
||||
* * **ngReadonly**
|
||||
* * **ngRequired**
|
||||
* * **ngDisabled**
|
||||
* * **ngValue**
|
||||
@@ -209,6 +213,9 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
.directive('ngChecked', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngChecked', 'aria-checked', nodeBlackList, false);
|
||||
}])
|
||||
.directive('ngReadonly', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nodeBlackList, false);
|
||||
}])
|
||||
.directive('ngRequired', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngRequired', 'aria-required', nodeBlackList, false);
|
||||
}])
|
||||
|
||||
@@ -396,6 +396,66 @@ describe('$aria', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('aria-readonly', function() {
|
||||
beforeEach(injectScopeAndCompiler);
|
||||
|
||||
they('should not attach itself to native $prop controls', {
|
||||
input: '<input ng-readonly="val">',
|
||||
textarea: '<textarea ng-readonly="val"></textarea>',
|
||||
select: '<select ng-readonly="val"></select>',
|
||||
button: '<button ng-readonly="val"></button>'
|
||||
}, function(tmpl) {
|
||||
var element = $compile(tmpl)(scope);
|
||||
scope.$apply('val = true');
|
||||
|
||||
expect(element.attr('readonly')).toBeDefined();
|
||||
expect(element.attr('aria-readonly')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should attach itself to custom controls', function() {
|
||||
compileElement('<div ng-readonly="val"></div>');
|
||||
expect(element.attr('aria-readonly')).toBe('false');
|
||||
|
||||
scope.$apply('val = true');
|
||||
expect(element.attr('aria-readonly')).toBe('true');
|
||||
|
||||
});
|
||||
|
||||
it('should not attach itself if an aria-readonly attribute is already present', function() {
|
||||
compileElement('<div ng-readonly="val" aria-readonly="userSetValue"></div>');
|
||||
|
||||
expect(element.attr('aria-readonly')).toBe('userSetValue');
|
||||
});
|
||||
|
||||
it('should always set aria-readonly to a boolean value', function() {
|
||||
compileElement('<div ng-readonly="val"></div>');
|
||||
|
||||
scope.$apply('val = "test angular"');
|
||||
expect(element.attr('aria-readonly')).toBe('true');
|
||||
|
||||
scope.$apply('val = null');
|
||||
expect(element.attr('aria-readonly')).toBe('false');
|
||||
|
||||
scope.$apply('val = {}');
|
||||
expect(element.attr('aria-readonly')).toBe('true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('aria-readonly when disabled', function() {
|
||||
beforeEach(configAriaProvider({
|
||||
ariaReadonly: false
|
||||
}));
|
||||
beforeEach(injectScopeAndCompiler);
|
||||
|
||||
it('should not add the aria-readonly attribute', function() {
|
||||
compileElement("<input ng-model='val' readonly>");
|
||||
expect(element.attr('aria-readonly')).toBeUndefined();
|
||||
|
||||
compileElement("<div ng-model='val' ng-readonly='true'></div>");
|
||||
expect(element.attr('aria-readonly')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('aria-required', function() {
|
||||
beforeEach(injectScopeAndCompiler);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user