@@ -4,10 +4,33 @@ import { requestAF } from '../../utils/dom'
4
4
5
5
const NAME = 'BAlert'
6
6
7
+ // Convert `show` value to a number
8
+ const parseCountDown = show => {
9
+ if ( show === '' || typeof show === 'boolean' ) {
10
+ return 0
11
+ }
12
+ show = parseInt ( show , 10 )
13
+ return show > 0 ? show : 0
14
+ }
15
+
16
+ // Convert `show` value to a boolean
17
+ const parseShow = show => {
18
+ if ( show === '' || show === true ) {
19
+ return true
20
+ }
21
+ if ( parseInt ( show , 10 ) < 1 ) {
22
+ // Boolean will always return false for the above comparison
23
+ return false
24
+ }
25
+ return Boolean ( show )
26
+ }
27
+
28
+ // Is a value number like (i.e. a number or a number as string)
29
+ const isNumericLike = value => ! isNaN ( parseInt ( value , 10 ) )
30
+
7
31
// @vue /component
8
32
export default {
9
33
name : NAME ,
10
- components : { BButtonClose } ,
11
34
model : {
12
35
prop : 'show' ,
13
36
event : 'input'
@@ -26,7 +49,7 @@ export default {
26
49
default : ( ) => getComponentConfig ( NAME , 'dismissLabel' )
27
50
} ,
28
51
show : {
29
- type : [ Boolean , Number ] ,
52
+ type : [ Boolean , Number , String ] ,
30
53
default : false
31
54
} ,
32
55
fade : {
@@ -37,71 +60,74 @@ export default {
37
60
data ( ) {
38
61
return {
39
62
countDownTimerId : null ,
40
- dismissed : false ,
41
- localShow : this . show ,
63
+ countDown : 0 ,
64
+ // If initially shown, we need to set these for SSR
65
+ localShow : parseShow ( this . show ) ,
42
66
showClass : this . fade && this . show
43
67
}
44
68
} ,
45
69
watch : {
46
70
show ( newVal ) {
47
- this . showChanged ( newVal )
71
+ this . countDown = parseCountDown ( newVal )
72
+ this . localShow = parseShow ( newVal )
73
+ } ,
74
+ countDown ( newVal ) {
75
+ this . clearTimer ( )
76
+ this . $emit ( 'dismiss-count-down' , newVal )
77
+ if ( this . show !== newVal ) {
78
+ // Update the v-model if needed
79
+ this . $emit ( 'input' , newVal )
80
+ }
81
+ if ( newVal > 0 ) {
82
+ this . localShow = true
83
+ this . countDownTimerId = setTimeout ( ( ) => {
84
+ this . countDown --
85
+ } , 1000 )
86
+ } else {
87
+ // Slightly delay the hide to allow any UI updates
88
+ this . $nextTick ( ( ) => {
89
+ requestAF ( ( ) => {
90
+ this . localShow = false
91
+ } )
92
+ } )
93
+ }
48
94
} ,
49
- dismissed ( newVal ) {
50
- if ( newVal ) {
51
- this . localShow = false
95
+ localShow ( newVal ) {
96
+ if ( ! newVal && ( this . dismissible || isNumericLike ( this . show ) ) ) {
97
+ // Only emit dismissed events for dismissible or auto dismissing alerts
52
98
this . $emit ( 'dismissed' )
53
99
}
100
+ if ( ! isNumericLike ( this . show ) && this . show !== newVal ) {
101
+ // Only emit booleans if we weren't passed a number via `this.show`
102
+ this . $emit ( 'input' , newVal )
103
+ }
54
104
}
55
105
} ,
106
+ created ( ) {
107
+ this . countDown = parseCountDown ( this . show )
108
+ this . localShow = parseShow ( this . show )
109
+ } ,
56
110
mounted ( ) {
57
- this . showChanged ( this . show )
111
+ this . countDown = parseCountDown ( this . show )
112
+ this . localShow = parseShow ( this . show )
58
113
} ,
59
- destroyed /* istanbul ignore next */ ( ) {
60
- this . clearCounter ( )
114
+ beforeDestroy ( ) {
115
+ this . clearTimer ( )
61
116
} ,
62
117
methods : {
63
118
dismiss ( ) {
64
- this . clearCounter ( )
65
- if ( typeof this . show === 'number' ) {
66
- this . $emit ( 'dismiss-count-down' , 0 )
67
- this . $emit ( 'input' , 0 )
68
- } else {
69
- this . $emit ( 'input' , false )
70
- }
71
- this . dismissed = true
119
+ this . clearTimer ( )
120
+ this . countDown = 0
121
+ this . localShow = false
72
122
} ,
73
- clearCounter ( ) {
123
+ clearTimer ( ) {
74
124
if ( this . countDownTimerId ) {
75
125
clearInterval ( this . countDownTimerId )
76
126
this . countDownTimerId = null
77
127
}
78
128
} ,
79
- showChanged ( show ) {
80
- // Reset counter status
81
- this . clearCounter ( )
82
- // Reset dismiss status
83
- this . dismissed = false
84
- // Set localShow state
85
- this . localShow = Boolean ( show )
86
- // No timer for boolean values
87
- if ( show === true || show === false || show === null || show === 0 ) {
88
- return
89
- }
90
- // Start counter (ensure we have an integer value)
91
- let dismissCountDown = parseInt ( show , 10 ) || 1
92
- this . countDownTimerId = setInterval ( ( ) => {
93
- if ( dismissCountDown < 1 ) {
94
- this . dismiss ( )
95
- return
96
- }
97
- dismissCountDown --
98
- this . $emit ( 'dismiss-count-down' , dismissCountDown )
99
- this . $emit ( 'input' , dismissCountDown )
100
- } , 1000 )
101
- } ,
102
129
onBeforeEnter ( ) {
103
130
if ( this . fade ) {
104
- // Add show class one frame after inserted, to make transitions work
105
131
requestAF ( ( ) => {
106
132
this . showClass = true
107
133
} )
@@ -113,12 +139,13 @@ export default {
113
139
} ,
114
140
render ( h ) {
115
141
const $slots = this . $slots
116
- let $alert = h ( false )
142
+ let $alert // undefined
117
143
if ( this . localShow ) {
118
144
let $dismissBtn = h ( false )
119
145
if ( this . dismissible ) {
146
+ // Add dismiss button
120
147
$dismissBtn = h (
121
- 'b-button-close' ,
148
+ BButtonClose ,
122
149
{ attrs : { 'aria-label' : this . dismissLabel } , on : { click : this . dismiss } } ,
123
150
[ $slots . dismiss ]
124
151
)
@@ -143,8 +170,6 @@ export default {
143
170
'transition' ,
144
171
{
145
172
props : {
146
- mode : 'out-in' ,
147
- // Disable use of built-in transition classes
148
173
'enter-class' : '' ,
149
174
'enter-active-class' : '' ,
150
175
'enter-to-class' : '' ,
0 commit comments