11<template >
2- <b-modal
3- id =" sessionModal"
4- ref =" sessionModal"
5- :title =" title"
6- modal-class =" session-timeout-modal"
7- backdrop-class =" session-timeout-backdrop"
8- footer-class =" pm-modal-footer"
9- no-close-on-backdrop
10- centered
11- no-close-button
12- >
13- <template #modal-header >
14- <h5 >{{ title }}</h5 >
15- </template >
16- <div v-if =" !isProcessing" >
17- <span v-html =" message" />
18- <div class =" progress" >
19- <div
20- class =" progress-bar progress-bar-striped"
21- role =" progressbar"
22- :style =" {width: percentage + '%'}"
23- >
24- <span
25- align =" left"
26- class =" pl-2"
27- >{{ moment().startOf('day').seconds(time).format('mm:ss') }}</span >
28- </div >
29- </div >
30- </div >
2+ <div >
313 <div
32- v-else
33- class =" d-flex align-items-center justify-content-center py-3"
4+ v-if =" shown"
5+ class =" session-timeout-overlay"
6+ role =" presentation"
347 >
35- <output
36- class =" spinner-border spinner-border-sm mr-2"
37- aria-live =" polite"
38- />
39- <span >{{ ("Processing...") }}</span >
40- </div >
41- <template #modal-footer >
42- <button
43- v-if =" !isProcessing"
44- type =" button"
45- class =" btn btn-outline-secondary ml-2"
46- :disabled =" isBusy"
47- @click =" logoutNow"
48- >
49- {{ ('LogOut') }}
50- </button >
51- <button
52- v-if =" !isProcessing"
53- type =" button"
54- class =" btn btn-secondary ml-2"
55- :disabled =" isBusy"
56- @click =" keepAlive"
8+ <dialog
9+ ref =" sessionDialog"
10+ class =" session-timeout-dialog"
11+ :aria-label =" title"
12+ open
13+ tabindex =" -1"
5714 >
58- {{ ('Stay Connected') }}
59- </button >
60- </template >
61- </b-modal >
15+ <header class =" session-timeout-header" >
16+ <h5 >{{ title }}</h5 >
17+ </header >
18+ <div class =" session-timeout-body" >
19+ <div v-if =" !isProcessing" >
20+ <span v-html =" message" />
21+ <div class =" progress" >
22+ <div
23+ class =" progress-bar progress-bar-striped"
24+ role =" progressbar"
25+ :style =" {width: percentage + '%'}"
26+ >
27+ <span
28+ align =" left"
29+ class =" pl-2"
30+ >{{ moment().startOf('day').seconds(time).format('mm:ss') }}</span >
31+ </div >
32+ </div >
33+ </div >
34+ <div
35+ v-else
36+ class =" d-flex align-items-center justify-content-center py-3"
37+ >
38+ <output
39+ class =" spinner-border spinner-border-sm mr-2"
40+ aria-live =" polite"
41+ />
42+ <span >{{ ("Processing...") }}</span >
43+ </div >
44+ </div >
45+ <footer class =" pm-modal-footer session-timeout-footer" >
46+ <button
47+ v-if =" !isProcessing"
48+ type =" button"
49+ class =" btn btn-outline-secondary ml-2"
50+ :disabled =" isBusy"
51+ @click =" logoutNow"
52+ >
53+ {{ ('LogOut') }}
54+ </button >
55+ <button
56+ v-if =" !isProcessing"
57+ type =" button"
58+ class =" btn btn-secondary ml-2"
59+ :disabled =" isBusy"
60+ @click =" keepAlive"
61+ >
62+ {{ ('Stay Connected') }}
63+ </button >
64+ </footer >
65+ </dialog >
66+ </div >
67+ </div >
6268</template >
6369
6470<script >
@@ -70,6 +76,8 @@ export default {
7076 errors: {},
7177 disabled: false ,
7278 localRenewing: false ,
79+ originalParent: null ,
80+ originalNextSibling: null ,
7381 };
7482 },
7583 computed: {
@@ -93,18 +101,62 @@ export default {
93101 shown (value ) {
94102 if (value) {
95103 this .resetProcessingState ();
96- }
97- if (value) {
98- this .$refs .sessionModal .show ();
104+ this .lockBodyScroll ();
105+ this .focusDialog ();
99106 } else {
100- this .$refs . sessionModal . hide ();
107+ this .unlockBodyScroll ();
101108 }
102109 },
103110 },
104111 mounted () {
112+ this .mountOverlayInBody ();
113+ if (this .shown ) {
114+ this .lockBodyScroll ();
115+ this .focusDialog ();
116+ }
105117 this .$emit (" show" );
106118 },
119+ beforeDestroy () {
120+ this .unlockBodyScroll ();
121+ this .restoreOverlayParent ();
122+ },
107123 methods: {
124+ mountOverlayInBody () {
125+ if (! document ? .body || this .$el .parentNode === document .body ) {
126+ return ;
127+ }
128+
129+ this .originalParent = this .$el .parentNode ;
130+ this .originalNextSibling = this .$el .nextSibling ;
131+ document .body .appendChild (this .$el );
132+ },
133+ restoreOverlayParent () {
134+ if (! this .originalParent || ! this .$el .parentNode ) {
135+ return ;
136+ }
137+
138+ this .$el .remove ();
139+ this .originalParent .insertBefore (this .$el , this .originalNextSibling );
140+ },
141+ lockBodyScroll () {
142+ document ? .body ? .classList .add (" session-timeout-open" );
143+ },
144+ unlockBodyScroll () {
145+ document ? .body ? .classList .remove (" session-timeout-open" );
146+ },
147+ focusDialog () {
148+ this .$nextTick (() => {
149+ globalThis .setTimeout (() => {
150+ const firstButton = this .$refs .sessionDialog ? .querySelector (" button:not([disabled])" );
151+ if (firstButton) {
152+ firstButton .focus ();
153+ return ;
154+ }
155+
156+ this .$refs .sessionDialog ? .focus ();
157+ }, 50 );
158+ });
159+ },
108160 resetProcessingState () {
109161 this .localRenewing = false ;
110162 this .disabled = false ;
@@ -193,11 +245,64 @@ export default {
193245< / script>
194246
195247< style>
196- .session - timeout- backdrop {
197- z- index: 20000 ! important;
248+ body .session - timeout- open {
249+ overflow: hidden;
250+ }
251+
252+ .session - timeout- overlay {
253+ align- items: center;
254+ background: rgba (0 , 0 , 0 , 0.5 );
255+ bottom: 0 ;
256+ display: flex;
257+ justify- content: center;
258+ left: 0 ;
259+ overflow- x: hidden;
260+ overflow- y: auto;
261+ padding: 1 .75rem ;
262+ position: fixed;
263+ right: 0 ;
264+ top: 0 ;
265+ z- index: 2147483647 ;
266+ }
267+
268+ .session - timeout- dialog {
269+ background: #fff;
270+ border- radius: 0 .3rem ;
271+ border: 0 ;
272+ box- shadow: 0 0 .5rem 1rem rgba (0 , 0 , 0 , 0.5 );
273+ display: flex;
274+ flex- direction: column;
275+ margin: 0 ;
276+ max- width: 500px ;
277+ outline: 0 ;
278+ padding: 0 ;
279+ position: relative;
280+ width: 100 % ;
281+ }
282+
283+ .session - timeout- header {
284+ align- items: flex- start;
285+ border- bottom: 1px solid #dee2e6;
286+ display: flex;
287+ padding: 1rem ;
288+ }
289+
290+ .session - timeout- header h5 {
291+ line- height: 1.5 ;
292+ margin: 0 ;
293+ }
294+
295+ .session - timeout- body {
296+ flex: 1 1 auto;
297+ padding: 1rem ;
298+ position: relative;
198299}
199300
200- .session - timeout- modal {
201- z- index: 20010 ! important;
301+ .session - timeout- footer {
302+ align- items: center;
303+ border- top: 1px solid #dee2e6;
304+ display: flex;
305+ justify- content: flex- end;
306+ padding: 0 .75rem ;
202307}
203308< / style>
0 commit comments