@@ -163,7 +163,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
163163 // {@link Attribute#$observe } on it. For more details please see {@link TableColumnResize }.
164164 scope . $isRendered = true ;
165165
166- // Deferred object that will be resolved when this modal is render .
166+ // Deferred object that will be resolved when this modal is rendered .
167167 var modalRenderDeferObj = $q . defer ( ) ;
168168 // Resolve render promise post-digest
169169 scope . $$postDigest ( function ( ) {
@@ -196,7 +196,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
196196
197197 /**
198198 * If something within the freshly-opened modal already has focus (perhaps via a
199- * directive that causes focus). then no need to try and focus anything.
199+ * directive that causes focus) then there's no need to try to focus anything.
200200 */
201201 if ( ! ( $document [ 0 ] . activeElement && element [ 0 ] . contains ( $document [ 0 ] . activeElement ) ) ) {
202202 var inputWithAutofocus = element [ 0 ] . querySelector ( '[autofocus]' ) ;
@@ -254,6 +254,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
254254 } ;
255255 var topModalIndex = 0 ;
256256 var previousTopOpenedModal = null ;
257+ var ARIA_HIDDEN_ATTRIBUTE_NAME = 'data-bootstrap-modal-aria-hidden-count' ;
257258
258259 //Modal focus behavior
259260 var tabbableSelector = 'a[href], area[href], input:not([disabled]):not([tabindex=\'-1\']), ' +
@@ -555,25 +556,74 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
555556
556557 openedWindows . top ( ) . value . modalDomEl = angularDomEl ;
557558 openedWindows . top ( ) . value . modalOpener = modalOpener ;
559+
560+ applyAriaHidden ( angularDomEl ) ;
561+
562+ function applyAriaHidden ( el ) {
563+ if ( ! el || el [ 0 ] . tagName === 'BODY' ) {
564+ return ;
565+ }
566+
567+ getSiblings ( el ) . forEach ( function ( sibling ) {
568+ var elemIsAlreadyHidden = sibling . getAttribute ( 'aria-hidden' ) === 'true' ,
569+ ariaHiddenCount = parseInt ( sibling . getAttribute ( ARIA_HIDDEN_ATTRIBUTE_NAME ) , 10 ) ;
570+
571+ if ( ! ariaHiddenCount ) {
572+ ariaHiddenCount = elemIsAlreadyHidden ? 1 : 0 ;
573+ }
574+
575+ sibling . setAttribute ( ARIA_HIDDEN_ATTRIBUTE_NAME , ariaHiddenCount + 1 ) ;
576+ sibling . setAttribute ( 'aria-hidden' , 'true' ) ;
577+ } ) ;
578+
579+ return applyAriaHidden ( el . parent ( ) ) ;
580+
581+ function getSiblings ( el ) {
582+ var children = el . parent ( ) ? el . parent ( ) . children ( ) : [ ] ;
583+
584+ return Array . prototype . filter . call ( children , function ( child ) {
585+ return child !== el [ 0 ] ;
586+ } ) ;
587+ }
588+ }
558589 } ;
559590
560591 function broadcastClosing ( modalWindow , resultOrReason , closing ) {
561592 return ! modalWindow . value . modalScope . $broadcast ( 'modal.closing' , resultOrReason , closing ) . defaultPrevented ;
562593 }
563594
595+ function unhideBackgroundElements ( ) {
596+ Array . prototype . forEach . call (
597+ document . querySelectorAll ( '[' + ARIA_HIDDEN_ATTRIBUTE_NAME + ']' ) ,
598+ function ( hiddenEl ) {
599+ var ariaHiddenCount = parseInt ( hiddenEl . getAttribute ( ARIA_HIDDEN_ATTRIBUTE_NAME ) , 10 ) ,
600+ newHiddenCount = ariaHiddenCount - 1 ;
601+ hiddenEl . setAttribute ( ARIA_HIDDEN_ATTRIBUTE_NAME , newHiddenCount ) ;
602+
603+ if ( ! newHiddenCount ) {
604+ hiddenEl . removeAttribute ( ARIA_HIDDEN_ATTRIBUTE_NAME ) ;
605+ hiddenEl . removeAttribute ( 'aria-hidden' ) ;
606+ }
607+ }
608+ ) ;
609+ }
610+
564611 $modalStack . close = function ( modalInstance , result ) {
565612 var modalWindow = openedWindows . get ( modalInstance ) ;
613+ unhideBackgroundElements ( ) ;
566614 if ( modalWindow && broadcastClosing ( modalWindow , result , true ) ) {
567615 modalWindow . value . modalScope . $$uibDestructionScheduled = true ;
568616 modalWindow . value . deferred . resolve ( result ) ;
569617 removeModalWindow ( modalInstance , modalWindow . value . modalOpener ) ;
570618 return true ;
571619 }
620+
572621 return ! modalWindow ;
573622 } ;
574623
575624 $modalStack . dismiss = function ( modalInstance , reason ) {
576625 var modalWindow = openedWindows . get ( modalInstance ) ;
626+ unhideBackgroundElements ( ) ;
577627 if ( modalWindow && broadcastClosing ( modalWindow , reason , false ) ) {
578628 modalWindow . value . modalScope . $$uibDestructionScheduled = true ;
579629 modalWindow . value . deferred . reject ( reason ) ;
@@ -596,6 +646,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
596646
597647 $modalStack . modalRendered = function ( modalInstance ) {
598648 var modalWindow = openedWindows . get ( modalInstance ) ;
649+ $modalStack . focusFirstFocusableElement ( $modalStack . loadFocusElementList ( modalWindow ) ) ;
599650 if ( modalWindow ) {
600651 modalWindow . value . renderDeferred . resolve ( ) ;
601652 }
0 commit comments