This repository has been archived by the owner on Mar 12, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
92 lines (69 loc) · 2.53 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
'use strict'; // requires CustomEvent polyfill for IE
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
var CustomEvent = require('custom-event');
var util = require('./util.js'); // the main landmark
var mainEl; // the element that will be trapped
var trappedEl; // collection of elements that get 'dirtied' with aria-hidden attr
var dirtyObjects;
function prepareAttribute(el, dirtyValue) {
return {
el: el,
cleanValue: el.getAttribute('aria-hidden'),
dirtyValue: dirtyValue
};
}
function dirtyAttribute(preparedObj) {
preparedObj.el.setAttribute('aria-hidden', preparedObj.dirtyValue);
}
function cleanAttribute(preparedObj) {
if (preparedObj.cleanValue) {
preparedObj.el.setAttribute('aria-hidden', preparedObj.cleanValue);
} else {
preparedObj.el.removeAttribute('aria-hidden');
}
}
function untrap() {
if (trappedEl) {
// restore 'dirtied' elements to their original state
dirtyObjects.forEach(function (item) {
return cleanAttribute(item);
});
dirtyObjects = []; // 're-enable' the main landmark
if (mainEl) {
mainEl.setAttribute('role', 'main');
} // let observers know the screenreader is now untrapped
trappedEl.dispatchEvent(new CustomEvent('screenreaderUntrap', {
bubbles: true
}));
trappedEl = null;
}
}
function trap(el) {
// ensure current trap is deactivated
untrap(); // update the trapped el reference
trappedEl = el; // update the main landmark reference
mainEl = document.querySelector('main, [role="main"]'); // we must remove the main landmark to avoid issues on voiceover iOS
if (mainEl) {
mainEl.setAttribute('role', 'presentation');
} // cache all ancestors, siblings & siblings of ancestors for trappedEl
var ancestors = util.getAncestors(trappedEl);
var siblings = util.getSiblings(trappedEl);
var siblingsOfAncestors = util.getSiblingsOfAncestors(trappedEl); // prepare elements
dirtyObjects = [prepareAttribute(trappedEl, 'false')].concat(ancestors.map(function (item) {
return prepareAttribute(item, 'false');
})).concat(siblings.map(function (item) {
return prepareAttribute(item, 'true');
})).concat(siblingsOfAncestors.map(function (item) {
return prepareAttribute(item, 'true');
})); // update DOM
dirtyObjects.forEach(function (item) {
return dirtyAttribute(item);
}); // let observers know the screenreader is now trapped
trappedEl.dispatchEvent(new CustomEvent('screenreaderTrap', {
bubbles: true
}));
}
module.exports = {
trap: trap,
untrap: untrap
};