2 * DO NOT EDIT THIS FILE.
3 * See the following change record for more information,
4 * https://www.drupal.org/node/2815083
8 (function ($, Drupal) {
9 function TabbingManager() {
13 function TabbingContext(options) {
17 $tabbableElements: $(),
19 $disabledElements: $(),
27 $.extend(TabbingManager.prototype, {
28 constrain: function constrain(elements) {
29 var il = this.stack.length;
30 for (var i = 0; i < il; i++) {
31 this.stack[i].deactivate();
34 var $elements = $(elements).find(':tabbable').addBack(':tabbable');
36 var tabbingContext = new TabbingContext({
37 level: this.stack.length,
38 $tabbableElements: $elements
41 this.stack.push(tabbingContext);
43 tabbingContext.activate();
45 $(document).trigger('drupalTabbingConstrained', tabbingContext);
47 return tabbingContext;
49 release: function release() {
50 var toActivate = this.stack.length - 1;
51 while (toActivate >= 0 && this.stack[toActivate].released) {
55 this.stack.splice(toActivate + 1);
57 if (toActivate >= 0) {
58 this.stack[toActivate].activate();
61 activate: function activate(tabbingContext) {
62 var $set = tabbingContext.$tabbableElements;
63 var level = tabbingContext.level;
65 var $disabledSet = $(':tabbable').not($set);
67 tabbingContext.$disabledElements = $disabledSet;
69 var il = $disabledSet.length;
70 for (var i = 0; i < il; i++) {
71 this.recordTabindex($disabledSet.eq(i), level);
74 $disabledSet.prop('tabindex', -1).prop('autofocus', false);
76 var $hasFocus = $set.filter('[autofocus]').eq(-1);
78 if ($hasFocus.length === 0) {
79 $hasFocus = $set.eq(0);
81 $hasFocus.trigger('focus');
83 deactivate: function deactivate(tabbingContext) {
84 var $set = tabbingContext.$disabledElements;
85 var level = tabbingContext.level;
87 for (var i = 0; i < il; i++) {
88 this.restoreTabindex($set.eq(i), level);
91 recordTabindex: function recordTabindex($el, level) {
92 var tabInfo = $el.data('drupalOriginalTabIndices') || {};
94 tabindex: $el[0].getAttribute('tabindex'),
95 autofocus: $el[0].hasAttribute('autofocus')
97 $el.data('drupalOriginalTabIndices', tabInfo);
99 restoreTabindex: function restoreTabindex($el, level) {
100 var tabInfo = $el.data('drupalOriginalTabIndices');
101 if (tabInfo && tabInfo[level]) {
102 var data = tabInfo[level];
104 $el[0].setAttribute('tabindex', data.tabindex);
106 $el[0].removeAttribute('tabindex');
108 if (data.autofocus) {
109 $el[0].setAttribute('autofocus', 'autofocus');
113 $el.removeData('drupalOriginalTabIndices');
115 var levelToDelete = level;
116 while (tabInfo.hasOwnProperty(levelToDelete)) {
117 delete tabInfo[levelToDelete];
120 $el.data('drupalOriginalTabIndices', tabInfo);
126 $.extend(TabbingContext.prototype, {
127 release: function release() {
128 if (!this.released) {
130 this.released = true;
131 Drupal.tabbingManager.release(this);
133 $(document).trigger('drupalTabbingContextReleased', this);
136 activate: function activate() {
137 if (!this.active && !this.released) {
139 Drupal.tabbingManager.activate(this);
141 $(document).trigger('drupalTabbingContextActivated', this);
144 deactivate: function deactivate() {
147 Drupal.tabbingManager.deactivate(this);
149 $(document).trigger('drupalTabbingContextDeactivated', this);
154 if (Drupal.tabbingManager) {
158 Drupal.tabbingManager = new TabbingManager();