diff --git a/src/base/constants.js b/src/base/constants.js index b0add2d0e09..42267130ef0 100644 --- a/src/base/constants.js +++ b/src/base/constants.js @@ -3,6 +3,7 @@ var Constant = { ROLE : { BUTTON : 'button', CHECKBOX : 'checkbox', + DIALOG : 'dialog', LIST : 'list', LIST_ITEM : 'listitem', RADIO : 'radio', diff --git a/src/base/utils.js b/src/base/utils.js index 9d8f9e9a836..9de0a1f5b53 100644 --- a/src/base/utils.js +++ b/src/base/utils.js @@ -46,6 +46,18 @@ var Util = { return offset ? letter.toUpperCase() : letter; }); }, + /** + * Selects 'n' words from a string + * for use in an HTML attribute + */ + stringFromTextBody: function stringFromTextBody(textBody, numWords) { + var string = textBody.trim(); + + if(string.split(/\s+/).length > numWords){ + string = textBody.split(/\s+/).slice(1, (numWords + 1)).join(" ") + '...'; + } + return string; + }, /** * Spread the arguments as individual parameters to the target function. diff --git a/src/components/dialog/dialog.js b/src/components/dialog/dialog.js index 2dcc873d0b5..3525b4401e2 100644 --- a/src/components/dialog/dialog.js +++ b/src/components/dialog/dialog.js @@ -4,7 +4,8 @@ */ angular.module('material.components.dialog', [ 'material.animations', - 'material.services.compiler' + 'material.services.compiler', + 'material.services.aria' ]) .directive('materialDialog', [ '$$rAF', @@ -17,6 +18,7 @@ angular.module('material.components.dialog', [ '$rootScope', '$materialEffects', '$animate', + '$aria', MaterialDialogService ]); @@ -61,7 +63,7 @@ function MaterialDialogDirective($$rAF) { *
* * Open a Dialog from this button! - * + * *
* * @@ -102,7 +104,7 @@ function MaterialDialogDirective($$rAF) { * @param {element=} appendTo The element to append the dialog to. Defaults to appending * to the root element of the application. */ -function MaterialDialogService($timeout, $materialCompiler, $rootElement, $rootScope, $materialEffects, $animate) { +function MaterialDialogService($timeout, $materialCompiler, $rootElement, $rootScope, $materialEffects, $animate, $aria) { var recentDialog; var dialogParent = $rootElement.find('body'); if ( !dialogParent.length ) { @@ -144,6 +146,8 @@ function MaterialDialogService($timeout, $materialCompiler, $rootElement, $rootS var closeButton = findCloseButton(); var backdrop; + configureAria(element.find('material-dialog')); + if (options.hasBackdrop) { backdrop = angular.element(''); $animate.enter(backdrop, options.appendTo, null); @@ -188,6 +192,10 @@ function MaterialDialogService($timeout, $materialCompiler, $rootElement, $rootS scope.$destroy(); scope = null; element = null; + + if(popInTarget !== null) { + popInTarget.focus(); + } }); } function onRootElementKeyup(e) { @@ -203,6 +211,24 @@ function MaterialDialogService($timeout, $materialCompiler, $rootElement, $rootS } }); + /** + * Inject ARIA-specific attributes appropriate for Dialogs + */ + function configureAria(element) { + var ROLE = Constant.ARIA.ROLE; + + $aria.update(element, { + 'role': ROLE.DIALOG + }); + + var dialogContent = element.find('.dialog-content'); + if(dialogContent.length === 0){ + dialogContent = element; + } + var defaultText = Util.stringFromTextBody(dialogContent.text(), 3); + $aria.expect(element, 'aria-label', defaultText); + } + return recentDialog; } } diff --git a/src/components/dialog/dialog.spec.js b/src/components/dialog/dialog.spec.js index 1ba68b4f660..2d3bef7bc9d 100644 --- a/src/components/dialog/dialog.spec.js +++ b/src/components/dialog/dialog.spec.js @@ -26,7 +26,22 @@ describe('$materialDialog', function() { var container = parent.find('.material-dialog-container'); expect(container.length).toBe(1); - expect(container.html().trim()).toEqual(template); + })); + + it('should have valid ARIA attributes', inject(function($materialDialog, $rootScope) { + var template = 'Hello'; + var parent = angular.element('
'); + + $materialDialog({ + template: template, + appendTo: parent + }); + + $rootScope.$apply(); + + var dialog = parent.find('material-dialog'); + expect(dialog.attr('role')).toBe('dialog'); + expect(dialog.attr('aria-label')).toEqual(dialog.text()); })); it('should escapeToClose == true', inject(function($materialDialog, $rootScope, $rootElement, $timeout, $materialEffects) {