-
Notifications
You must be signed in to change notification settings - Fork 0
/
accordion.js
126 lines (106 loc) · 4.56 KB
/
accordion.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
* This content is licensed according to the W3C Software License at
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* Simple accordion pattern example
*/
'use strict';
Array.prototype.slice.call(document.querySelectorAll('.Accordion')).forEach(function (accordion) {
// Allow for multiple accordion sections to be expanded at the same time
var allowMultiple = accordion.hasAttribute('data-allow-multiple');
// Allow for each toggle to both open and close individually
var allowToggle = (allowMultiple) ? allowMultiple : accordion.hasAttribute('data-allow-toggle');
// Create the array of toggle elements for the accordion group
var triggers = Array.prototype.slice.call(accordion.querySelectorAll('.Accordion-trigger'));
var panels = Array.prototype.slice.call(accordion.querySelectorAll('.Accordion-panel'));
accordion.addEventListener('click', function (event) {
var target = event.target;
if (target.classList.contains('Accordion-trigger')) {
// Check if the current toggle is expanded.
var isExpanded = target.getAttribute('aria-expanded') == 'true';
var active = accordion.querySelector('[aria-expanded="true"]');
// without allowMultiple, close the open accordion
if (!allowMultiple && active && active !== target) {
// Set the expanded state on the triggering element
active.setAttribute('aria-expanded', 'false');
// Hide the accordion sections, using aria-controls to specify the desired section
document.getElementById(active.getAttribute('aria-controls')).setAttribute('hidden', '');
// When toggling is not allowed, clean up disabled state
if (!allowToggle) {
active.removeAttribute('aria-disabled');
}
}
if (!isExpanded) {
// Set the expanded state on the triggering element
target.setAttribute('aria-expanded', 'true');
// Hide the accordion sections, using aria-controls to specify the desired section
document.getElementById(target.getAttribute('aria-controls')).removeAttribute('hidden');
// If toggling is not allowed, set disabled state on trigger
if (!allowToggle) {
target.setAttribute('aria-disabled', 'true');
}
}
else if (allowToggle && isExpanded) {
// Set the expanded state on the triggering element
target.setAttribute('aria-expanded', 'false');
// Hide the accordion sections, using aria-controls to specify the desired section
document.getElementById(target.getAttribute('aria-controls')).setAttribute('hidden', '');
}
event.preventDefault();
}
});
// Bind keyboard behaviors on the main accordion container
accordion.addEventListener('keydown', function (event) {
var target = event.target;
var key = event.which.toString();
// 33 = Page Up, 34 = Page Down
var ctrlModifier = (event.ctrlKey && key.match(/33|34/));
// Is this coming from an accordion header?
if (target.classList.contains('Accordion-trigger')) {
// Up/ Down arrow and Control + Page Up/ Page Down keyboard operations
// 38 = Up, 40 = Down
if (key.match(/38|40/) || ctrlModifier) {
var index = triggers.indexOf(target);
var direction = (key.match(/34|40/)) ? 1 : -1;
var length = triggers.length;
var newIndex = (index + length + direction) % length;
triggers[newIndex].focus();
event.preventDefault();
}
else if (key.match(/35|36/)) {
// 35 = End, 36 = Home keyboard operations
switch (key) {
// Go to first accordion
case '36':
triggers[0].focus();
break;
// Go to last accordion
case '35':
triggers[triggers.length - 1].focus();
break;
}
event.preventDefault();
}
}
else if (ctrlModifier) {
// Control + Page Up/ Page Down keyboard operations
// Catches events that happen inside of panels
panels.forEach(function (panel, index) {
if (panel.contains(target)) {
triggers[index].focus();
event.preventDefault();
}
});
}
});
// Minor setup: will set disabled state, via aria-disabled, to an
// expanded/ active accordion which is not allowed to be toggled close
if (!allowToggle) {
// Get the first expanded/ active accordion
var expanded = accordion.querySelector('[aria-expanded="true"]');
// If an expanded/ active accordion is found, disable
if (expanded) {
expanded.setAttribute('aria-disabled', 'true');
}
}
});