|
91 | 91 | open: function() {
|
92 | 92 | var m = this;
|
93 | 93 | this.block();
|
| 94 | + // Store previous focus |
| 95 | + this.previousFocus = document.activeElement; |
| 96 | + |
94 | 97 | this.anchor.blur();
|
95 | 98 | if(this.options.doFade) {
|
96 | 99 | setTimeout(function() {
|
|
156 | 159 | } else {
|
157 | 160 | this.$elm.css('display', 'inline-block');
|
158 | 161 | }
|
| 162 | + this.trapFocus(); |
159 | 163 | this.$elm.trigger($.modal.OPEN, [this._ctx()]);
|
160 | 164 | },
|
161 | 165 |
|
|
172 | 176 | _this.$elm.trigger($.modal.AFTER_CLOSE, [_this._ctx()]);
|
173 | 177 | });
|
174 | 178 | }
|
| 179 | + this.releaseFocus(); |
175 | 180 | this.$elm.trigger($.modal.CLOSE, [this._ctx()]);
|
176 | 181 | },
|
177 | 182 |
|
|
187 | 192 | if (this.spinner) this.spinner.remove();
|
188 | 193 | },
|
189 | 194 |
|
| 195 | + // Trap focus in modal for screen readers & keyboard navigation |
| 196 | + trapFocus: function() { |
| 197 | + // All focusable elements |
| 198 | + var focusableElements = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'; |
| 199 | + |
| 200 | + var firstFocusableElement = this.$elm[0].querySelectorAll(focusableElements)[0]; // get first element to be focused inside modal |
| 201 | + var focusableContent = this.$elm[0].querySelectorAll(focusableElements); |
| 202 | + var lastFocusableElement = focusableContent[focusableContent.length - 1]; // get last element to be focused inside modal |
| 203 | + |
| 204 | + |
| 205 | + $(this.$elm).on('keydown', function(e) { |
| 206 | + let isTabPressed = e.key === 'Tab' || e.keyCode === 9; |
| 207 | + |
| 208 | + if (!isTabPressed) { |
| 209 | + return; |
| 210 | + } |
| 211 | + |
| 212 | + if (e.shiftKey) { // if shift key pressed for shift + tab combination |
| 213 | + if (document.activeElement === firstFocusableElement) { |
| 214 | + lastFocusableElement.focus(); // add focus for the last focusable element |
| 215 | + e.preventDefault(); |
| 216 | + } |
| 217 | + } else { // if tab key is pressed |
| 218 | + if (document.activeElement === lastFocusableElement) { // if focused has reached to last focusable element then focus first focusable element after pressing tab |
| 219 | + firstFocusableElement.focus(); // add focus for the first focusable element |
| 220 | + e.preventDefault(); |
| 221 | + } |
| 222 | + } |
| 223 | + }); |
| 224 | + |
| 225 | + firstFocusableElement.focus(); |
| 226 | + }, |
| 227 | + |
| 228 | + releaseFocus: function() { |
| 229 | + $(this.$elm).off('keydown'); |
| 230 | + |
| 231 | + // Restore previous focus |
| 232 | + this.previousFocus.focus(); |
| 233 | + }, |
| 234 | + |
190 | 235 | //Return context for custom events
|
191 | 236 | _ctx: function() {
|
192 | 237 | return { elm: this.$elm, $elm: this.$elm, $blocker: this.$blocker, options: this.options, $anchor: this.anchor };
|
|
0 commit comments