@@ -163,7 +163,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
163
163
// {@link Attribute#$observe } on it. For more details please see {@link TableColumnResize }.
164
164
scope . $isRendered = true ;
165
165
166
- // Deferred object that will be resolved when this modal is render .
166
+ // Deferred object that will be resolved when this modal is rendered .
167
167
var modalRenderDeferObj = $q . defer ( ) ;
168
168
// Resolve render promise post-digest
169
169
scope . $$postDigest ( function ( ) {
@@ -196,7 +196,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
196
196
197
197
/**
198
198
* 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.
200
200
*/
201
201
if ( ! ( $document [ 0 ] . activeElement && element [ 0 ] . contains ( $document [ 0 ] . activeElement ) ) ) {
202
202
var inputWithAutofocus = element [ 0 ] . querySelector ( '[autofocus]' ) ;
@@ -254,6 +254,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
254
254
} ;
255
255
var topModalIndex = 0 ;
256
256
var previousTopOpenedModal = null ;
257
+ var ARIA_HIDDEN_ATTRIBUTE_NAME = 'data-bootstrap-modal-aria-hidden-count' ;
257
258
258
259
//Modal focus behavior
259
260
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
555
556
556
557
openedWindows . top ( ) . value . modalDomEl = angularDomEl ;
557
558
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
+ }
558
589
} ;
559
590
560
591
function broadcastClosing ( modalWindow , resultOrReason , closing ) {
561
592
return ! modalWindow . value . modalScope . $broadcast ( 'modal.closing' , resultOrReason , closing ) . defaultPrevented ;
562
593
}
563
594
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
+
564
611
$modalStack . close = function ( modalInstance , result ) {
565
612
var modalWindow = openedWindows . get ( modalInstance ) ;
613
+ unhideBackgroundElements ( ) ;
566
614
if ( modalWindow && broadcastClosing ( modalWindow , result , true ) ) {
567
615
modalWindow . value . modalScope . $$uibDestructionScheduled = true ;
568
616
modalWindow . value . deferred . resolve ( result ) ;
569
617
removeModalWindow ( modalInstance , modalWindow . value . modalOpener ) ;
570
618
return true ;
571
619
}
620
+
572
621
return ! modalWindow ;
573
622
} ;
574
623
575
624
$modalStack . dismiss = function ( modalInstance , reason ) {
576
625
var modalWindow = openedWindows . get ( modalInstance ) ;
626
+ unhideBackgroundElements ( ) ;
577
627
if ( modalWindow && broadcastClosing ( modalWindow , reason , false ) ) {
578
628
modalWindow . value . modalScope . $$uibDestructionScheduled = true ;
579
629
modalWindow . value . deferred . reject ( reason ) ;
@@ -596,6 +646,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
596
646
597
647
$modalStack . modalRendered = function ( modalInstance ) {
598
648
var modalWindow = openedWindows . get ( modalInstance ) ;
649
+ $modalStack . focusFirstFocusableElement ( $modalStack . loadFocusElementList ( modalWindow ) ) ;
599
650
if ( modalWindow ) {
600
651
modalWindow . value . renderDeferred . resolve ( ) ;
601
652
}
0 commit comments