@@ -25,6 +25,9 @@ const OBSERVER_CONFIG = {
25
25
attributeFilter : [ 'style' , 'class' ]
26
26
}
27
27
28
+ // Options for DOM event listeners
29
+ const EVT_OPTIONS = { passive : true , capture : false }
30
+
28
31
export const props = {
29
32
title : {
30
33
type : String ,
@@ -221,8 +224,9 @@ export default Vue.extend({
221
224
is_transitioning : false , // Used for style control
222
225
is_show : false , // Used for style control
223
226
is_block : false , // Used for style control
224
- is_opening : false , // Semaphore for preventing incorrect modal open counts
225
- is_closing : false , // Semaphore for preventing incorrect modal open counts
227
+ is_opening : false , // To sginal that modal is in the process of opening
228
+ is_closing : false , // To signal that the modal is in the process of closing
229
+ ignoreBackdropClick : false , // Used to signify if click out listener should ignore the click
226
230
isModalOverflowing : false ,
227
231
return_focus : this . returnFocus || null ,
228
232
// The following items are controlled by the modalManager instance
@@ -517,12 +521,30 @@ export default Vue.extend({
517
521
this . emitOnRoot ( `bv::modal::${ type } ` , bvEvt , bvEvt . modalId )
518
522
} ,
519
523
// UI event handlers
524
+ onDialogMousedown ( evt ) {
525
+ // Watch to see if the matching mouseup event occurs outside the dialog
526
+ // And if it does, cancel the clickout handler
527
+ const modal = this . $refs . modal
528
+ const onceModalMouseup = evt => {
529
+ eventOff ( modal , 'mouseup' , onceModalMouseup , EVT_OPTIONS )
530
+ if ( evt . target === modal ) {
531
+ this . ignoreBackdropClick = true
532
+ }
533
+ }
534
+ eventOn ( modal , 'mouseup' , onceModalMouseup , EVT_OPTIONS )
535
+ } ,
520
536
onClickOut ( evt ) {
521
537
// Do nothing if not visible, backdrop click disabled, or element
522
538
// that generated click event is no longer in document
523
539
if ( ! this . is_visible || this . noCloseOnBackdrop || ! contains ( document , evt . target ) ) {
524
540
return
525
541
}
542
+ if ( this . ignoreBackdropClick ) {
543
+ // Click was initiated inside the modal content, but finished outside
544
+ // Set by the above onDialogMousedown handler
545
+ this . ignoreBackdropClick = false
546
+ return
547
+ }
526
548
// If backdrop clicked, hide modal
527
549
if ( ! contains ( this . $refs . content , evt . target ) ) {
528
550
this . hide ( 'backdrop' )
@@ -552,15 +574,14 @@ export default Vue.extend({
552
574
// Turn on/off focusin listener
553
575
setEnforceFocus ( on ) {
554
576
const method = on ? eventOn : eventOff
555
- method ( document , 'focusin' , this . focusHandler , { passive : true , capture : false } )
577
+ method ( document , 'focusin' , this . focusHandler , EVT_OPTIONS )
556
578
} ,
557
579
// Resize listener
558
580
setResizeEvent ( on ) {
559
- const options = { passive : true , capture : false }
560
581
const method = on ? eventOn : eventOff
561
582
// These events should probably also check if body is overflowing
562
- method ( window , 'resize' , this . checkModalOverflow , options )
563
- method ( window , 'orientationchange' , this . checkModalOverflow , options )
583
+ method ( window , 'resize' , this . checkModalOverflow , EVT_OPTIONS )
584
+ method ( window , 'orientationchange' , this . checkModalOverflow , EVT_OPTIONS )
564
585
} ,
565
586
// Root listener handlers
566
587
showHandler ( id , triggerEl ) {
@@ -758,7 +779,10 @@ export default Vue.extend({
758
779
'div' ,
759
780
{
760
781
staticClass : 'modal-dialog' ,
761
- class : this . dialogClasses
782
+ class : this . dialogClasses ,
783
+ on : {
784
+ mousedown : this . onDialogMousedown
785
+ }
762
786
} ,
763
787
[ modalContent ]
764
788
)
0 commit comments