|
85 | 85 | open: function() {
|
86 | 86 | var m = this;
|
87 | 87 | this.block();
|
| 88 | + // Store previous focus |
| 89 | + this.previousFocus = document.activeElement; |
| 90 | + |
88 | 91 | this.anchor.blur();
|
89 | 92 | if(this.options.doFade) {
|
90 | 93 | setTimeout(function() {
|
|
148 | 151 | } else {
|
149 | 152 | this.$elm.css('display', 'inline-block');
|
150 | 153 | }
|
| 154 | + this.trapFocus(); |
151 | 155 | this.$elm.trigger($.modal.OPEN, [this._ctx()]);
|
152 | 156 | },
|
153 | 157 |
|
|
164 | 168 | _this.$elm.trigger($.modal.AFTER_CLOSE, [_this._ctx()]);
|
165 | 169 | });
|
166 | 170 | }
|
| 171 | + this.releaseFocus(); |
167 | 172 | this.$elm.trigger($.modal.CLOSE, [this._ctx()]);
|
168 | 173 | },
|
169 | 174 |
|
|
179 | 184 | if (this.spinner) this.spinner.remove();
|
180 | 185 | },
|
181 | 186 |
|
| 187 | + // Trap focus in modal for screen readers & keyboard navigation |
| 188 | + trapFocus: function() { |
| 189 | + // All focusable elements |
| 190 | + var focusableElements = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'; |
| 191 | + |
| 192 | + var firstFocusableElement = this.$elm[0].querySelectorAll(focusableElements)[0]; // get first element to be focused inside modal |
| 193 | + var focusableContent = this.$elm[0].querySelectorAll(focusableElements); |
| 194 | + var lastFocusableElement = focusableContent[focusableContent.length - 1]; // get last element to be focused inside modal |
| 195 | + |
| 196 | + |
| 197 | + $(this.$elm).on('keydown', function(e) { |
| 198 | + let isTabPressed = e.key === 'Tab' || e.keyCode === 9; |
| 199 | + |
| 200 | + if (!isTabPressed) { |
| 201 | + return; |
| 202 | + } |
| 203 | + |
| 204 | + if (e.shiftKey) { // if shift key pressed for shift + tab combination |
| 205 | + if (document.activeElement === firstFocusableElement) { |
| 206 | + lastFocusableElement.focus(); // add focus for the last focusable element |
| 207 | + e.preventDefault(); |
| 208 | + } |
| 209 | + } else { // if tab key is pressed |
| 210 | + if (document.activeElement === lastFocusableElement) { // if focused has reached to last focusable element then focus first focusable element after pressing tab |
| 211 | + firstFocusableElement.focus(); // add focus for the first focusable element |
| 212 | + e.preventDefault(); |
| 213 | + } |
| 214 | + } |
| 215 | + }); |
| 216 | + |
| 217 | + firstFocusableElement.focus(); |
| 218 | + }, |
| 219 | + |
| 220 | + releaseFocus: function() { |
| 221 | + $(this.$elm).off('keydown'); |
| 222 | + |
| 223 | + // Restore previous focus |
| 224 | + this.previousFocus.focus(); |
| 225 | + }, |
| 226 | + |
182 | 227 | //Return context for custom events
|
183 | 228 | _ctx: function() {
|
184 | 229 | return { elm: this.$elm, $elm: this.$elm, $blocker: this.$blocker, options: this.options, $anchor: this.anchor };
|
|
0 commit comments