a11y-toggle.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /*
  2. MIT License
  3. Copyright (c) 2016 Edenspiekermann
  4. */
  5. (function () {
  6. 'use strict';
  7. var internalId = 0;
  8. var togglesMap = {};
  9. var targetsMap = {};
  10. function $ (selector, context) {
  11. return Array.prototype.slice.call(
  12. (context || document).querySelectorAll(selector)
  13. );
  14. }
  15. function getClosestToggle (element) {
  16. if (element.closest) {
  17. return element.closest('[data-a11y-toggle]');
  18. }
  19. while (element) {
  20. if (element.nodeType === 1 && element.hasAttribute('data-a11y-toggle')) {
  21. return element;
  22. }
  23. element = element.parentNode;
  24. }
  25. return null;
  26. }
  27. function handleToggle (toggle) {
  28. var target = toggle && targetsMap[toggle.getAttribute('aria-controls')];
  29. if (!target) {
  30. return false;
  31. }
  32. var toggles = togglesMap['#' + target.id];
  33. var isExpanded = target.getAttribute('aria-hidden') === 'false';
  34. target.setAttribute('aria-hidden', isExpanded);
  35. toggles.forEach(function (toggle) {
  36. toggle.setAttribute('aria-expanded', !isExpanded);
  37. });
  38. }
  39. var initA11yToggle = function (context) {
  40. togglesMap = $('[data-a11y-toggle]', context).reduce(function (acc, toggle) {
  41. var selector = '#' + toggle.getAttribute('data-a11y-toggle');
  42. acc[selector] = acc[selector] || [];
  43. acc[selector].push(toggle);
  44. return acc;
  45. }, togglesMap);
  46. var targets = Object.keys(togglesMap);
  47. targets.length && $(targets).forEach(function (target) {
  48. var toggles = togglesMap['#' + target.id];
  49. var isExpanded = target.hasAttribute('data-a11y-toggle-open');
  50. var labelledby = [];
  51. toggles.forEach(function (toggle) {
  52. toggle.id || toggle.setAttribute('id', 'a11y-toggle-' + internalId++);
  53. toggle.setAttribute('aria-controls', target.id);
  54. toggle.setAttribute('aria-expanded', isExpanded);
  55. labelledby.push(toggle.id);
  56. });
  57. target.setAttribute('aria-hidden', !isExpanded);
  58. target.hasAttribute('aria-labelledby') || target.setAttribute('aria-labelledby', labelledby.join(' '));
  59. targetsMap[target.id] = target;
  60. });
  61. };
  62. document.addEventListener('DOMContentLoaded', function () {
  63. initA11yToggle();
  64. });
  65. document.addEventListener('click', function (event) {
  66. var toggle = getClosestToggle(event.target);
  67. handleToggle(toggle);
  68. });
  69. document.addEventListener('keyup', function (event) {
  70. if (event.which === 13 || event.which === 32) {
  71. var toggle = getClosestToggle(event.target);
  72. if (toggle && toggle.getAttribute('role') === 'button') {
  73. handleToggle(toggle);
  74. }
  75. }
  76. });
  77. window && (window.a11yToggle = initA11yToggle);
  78. })();