|
11 | 11 | <div key="modal" :id="id"
|
12 | 12 | v-show="visible"
|
13 | 13 | :class="['modal',{fade :fade}]"
|
| 14 | + role="dialog" |
14 | 15 | @click="onClickOut($event)"
|
| 16 | + @keyup.esc="onEsc($event)" |
15 | 17 | >
|
16 | 18 |
|
17 | 19 | <div :class="['modal-dialog','modal-'+size]">
|
18 |
| - <div class="modal-content" @click.stop> |
19 |
| - |
20 |
| - <div class="modal-header" v-if="!hideHeader"> |
| 20 | + <div class="modal-content" |
| 21 | + tabindex="-1" |
| 22 | + role="document" |
| 23 | + ref="content" |
| 24 | + :aria-labeledby="hideHeader ? '' : (id + '_modal_title')" |
| 25 | + :aria-describedby="id + '_modal_body'" |
| 26 | + @click.stop |
| 27 | + > |
| 28 | + |
| 29 | + <header class="modal-header" v-if="!hideHeader"> |
21 | 30 | <slot name="modal-header">
|
22 |
| - <h5 class="modal-title"> |
| 31 | + <h5 class="modal-title" :id="id + '_modal_title'"> |
23 | 32 | <slot name="modal-title">{{title}}</slot>
|
24 | 33 | </h5>
|
25 |
| - <button type="button" class="close" aria-label="Close" @click="hide"> |
| 34 | + <button type="button" |
| 35 | + v-if="!hideHeaderClose" |
| 36 | + class="close" |
| 37 | + :aria-label="closeTitle" |
| 38 | + @click="hide" |
| 39 | + > |
26 | 40 | <span aria-hidden="true">×</span>
|
27 | 41 | </button>
|
28 | 42 | </slot>
|
29 |
| - </div> |
| 43 | + </header> |
30 | 44 |
|
31 |
| - <div class="modal-body"> |
| 45 | + <div class="modal-body" :id="id + '_modal_body'"> |
32 | 46 | <slot></slot>
|
33 | 47 | </div>
|
34 | 48 |
|
35 |
| - <div class="modal-footer" v-if="!hideFooter"> |
| 49 | + <footer class="modal-footer" v-if="!hideFooter"> |
36 | 50 | <slot name="modal-footer">
|
37 | 51 | <b-btn variant="secondary" @click="hide(false)">{{closeTitle}}</b-btn>
|
38 | 52 | <b-btn variant="primary" @click="hide(true)">{{okTitle}}</b-btn>
|
39 | 53 | </slot>
|
40 |
| - </div> |
| 54 | + </footer> |
41 | 55 |
|
42 | 56 | </div>
|
43 | 57 | </div>
|
|
108 | 122 | type: Boolean,
|
109 | 123 | default: true
|
110 | 124 | },
|
| 125 | + closeOnEsc: { |
| 126 | + type: Boolean, |
| 127 | + default: true |
| 128 | + }, |
111 | 129 | hideHeader: {
|
112 | 130 | type: Boolean,
|
113 | 131 | default: false
|
114 | 132 | },
|
115 | 133 | hideFooter: {
|
116 | 134 | type: Boolean,
|
117 | 135 | default: false
|
| 136 | + }, |
| 137 | + hideHeaderClose: { |
| 138 | + type: Boolean, |
| 139 | + default: false |
118 | 140 | }
|
119 | 141 | },
|
120 | 142 | methods: {
|
|
163 | 185 | this.hide();
|
164 | 186 | }
|
165 | 187 | },
|
166 |
| - pressedButton(e) { |
167 |
| - // If not visible don't do anything |
168 |
| - if (!this.visible) { |
169 |
| - return; |
170 |
| - } |
171 |
| -
|
172 |
| - // Support for esc key press |
173 |
| - const key = e.which || e.keyCode; |
174 |
| - if (key === 27) { // 27 is esc |
| 188 | + onEsc() { |
| 189 | + // If ESC presses, hide modal |
| 190 | + if (this.visible && this.closeOnEsc) { |
175 | 191 | this.hide();
|
176 | 192 | }
|
177 | 193 | },
|
178 | 194 | afterEnter(el) {
|
179 | 195 | // Add show class to keep el showed just after transition is ended,
|
180 | 196 | // Because transition removes all used classes
|
181 | 197 | el.classList.add('show');
|
| 198 | + }, |
| 199 | + enforceFocus(e) { |
| 200 | + // If focus leaves modal, bring it back |
| 201 | + // eventListener bound on document |
| 202 | + if (this.visible && |
| 203 | + document !== e.target && |
| 204 | + this.$refs.content && |
| 205 | + this.$refs.content !== e.target && |
| 206 | + !this.$refs.content.contains(e.target) { |
| 207 | + this.$refs.content.focus(); |
| 208 | + } |
182 | 209 | }
|
183 | 210 | },
|
184 | 211 | created() {
|
|
196 | 223 | },
|
197 | 224 | mounted() {
|
198 | 225 | if (typeof document !== 'undefined') {
|
199 |
| - document.addEventListener('keydown', this.pressedButton); |
| 226 | + document.addEventListener('focus', this.enforceFocus); |
200 | 227 | }
|
201 | 228 | },
|
202 | 229 | destroyed() {
|
203 | 230 | if (typeof document !== 'undefined') {
|
204 |
| - document.removeEventListener('keydown', this.pressedButton); |
| 231 | + document.removeEventListener('focus', this.enforceFocus); |
205 | 232 | }
|
206 | 233 | }
|
207 | 234 | };
|
|
0 commit comments