1var a11ySlideMenu = function(options) { 2 var defaultOptions = { 3 'direction' : 'right', 4 'toggler': "#a11yMenuToggler", 5 'page': '#content', 6 'panel': '.a11y-sliding-menu__panel', 7 'closeButton': "#closeSlideMenu" 8 } 9 10 options = typeof options !== 'undefined' ? options : defaultOptions; 11 12 this.options = mergeObjects(defaultOptions, options) 13 14 this.initSlideMenu(this.options) 15 this.openSlideMenu(this.options) 16 17}; 18 19 20a11ySlideMenu.prototype.initSlideMenu = function(props) { 21 var body = document.body 22 var page = returnElement(props.page) 23 var panel = returnElement(props.panel) 24 25 body.classList.add('a11y-sliding-menu') 26 body.classList.add('a11y-sliding-menu--hidden') 27 body.classList.add('a11y-sliding-menu-direction--' + props.direction) 28 29 if (panel !== null) { 30 panel.setAttribute('aria-hidden', 'true') 31 panel.setAttribute('tabIndex', '-1') 32 } 33 if (page !== null) { 34 page.classList.add('a11y-sliding-menu__page') 35 createShader(page) 36 } 37} 38a11ySlideMenu.prototype.openSlideMenu = function(props) { 39 var button = returnElement(props.toggler); 40 var page = returnElement(props.page) 41 var panel = returnElement(props.panel) 42 var insideCloseButton = returnElement(props.closeButton) 43 if (button !== null) { 44 45 button.addEventListener('click',function (){ 46 var ariaExpanded = button.getAttribute('aria-expanded') 47 if (ariaExpanded === 'false') { 48 document.body.classList.remove('a11y-sliding-menu--hidden') 49 document.body.classList.add('a11y-sliding-menu--visible') 50 button.setAttribute('aria-expanded', 'true') 51 panel.setAttribute('aria-hidden','false') 52 panel.setAttribute('tabIndex','0') 53 page.setAttribute('tabIndex', '-1') 54 55 // After opening menu focous on first element inside panel 56 focusOnFirstElement(panel) 57 58 // Close panel by click close button at bottom 59 if (insideCloseButton !== undefined) { 60 insideCloseButton.addEventListener('click', function () { 61 document.body.classList.remove('a11y-sliding-menu--visible') 62 document.body.classList.add('a11y-sliding-menu--hidden') 63 button.setAttribute('aria-expanded', 'false') 64 panel.setAttribute('aria-hidden','true') 65 panel.setAttribute('aria-hidden','-1') 66 page.setAttribute('tabIndex', '0') 67 }) 68 } 69 70 71 } else { 72 document.body.classList.remove('a11y-sliding-menu--visible') 73 document.body.classList.add('a11y-sliding-menu--hidden') 74 button.setAttribute('aria-expanded', 'false') 75 panel.setAttribute('aria-hidden','true') 76 panel.setAttribute('aria-hidden','-1') 77 page.setAttribute('tabIndex', '0') 78 79 } 80 81 },false) 82 83 // Clos slide menu 84 document.addEventListener("click", clickOutside, false); 85 document.addEventListener('keydown', closeByEsc, false); 86 87 88 } else { 89 console.log('A11Y Slide open eror, check page and toggler elements') 90 } 91} 92 93a11ySlideMenu.prototype.closeSlideMenu = function(props) { 94 // close by clicking outside 95 closeByClickingOutside(props) 96} 97 98// 99// https://stackoverflow.com/questions/30498318/es5-object-assign-equivalent 100function mergeObjects(){ 101 var res = {}; 102 for(var i = 0;i<arguments.length;i++){ 103 for(var x in arguments[i]){ 104 res[x] = arguments[i][x]; 105 }; 106 }; 107 return res; 108}; 109 110function createShader(parent) { 111 var shader = document.createElement('div') 112 shader.classList.add('a11y-sliding-menu__shader') 113 parent.parentElement.insertBefore(shader, parent) 114} 115function clickOutside(e) { 116 var button = returnElement("#a11yMenuToggler"); 117 var panel = returnElement("#a11ySlidingMenu"); 118 var page = returnElement("#content") 119 120 if (!button.contains(e.target)) { 121 var inside = panel.contains(e.target); 122 123 if (!inside) { 124 document.body.classList.remove('a11y-sliding-menu--visible') 125 document.body.classList.add('a11y-sliding-menu--hidden') 126 button.setAttribute('aria-expanded', 'false') 127 panel.setAttribute('aria-hidden','true') 128 panel.setAttribute('tabIndex','-1') 129 page.setAttribute('tabIndex','0') 130 } 131 } 132} 133 134function closeByEsc(e) { 135 var button = returnElement("#a11yMenuToggler"); 136 var panel = returnElement("#a11ySlidingMenu"); 137 var page = returnElement("#content") 138 139 var key = e.key; // const {key} = event; in ES6+ 140 if (key === "Escape") { 141 document.body.classList.remove('a11y-sliding-menu--visible') 142 document.body.classList.add('a11y-sliding-menu--hidden') 143 button.setAttribute('aria-expanded', 'false') 144 panel.setAttribute('aria-hidden', 'true') 145 panel.setAttribute('tabIndex', '-1') 146 page.setAttribute('tabIndex', '0') 147 } 148} 149 150function returnElement(elem) { 151 if (elem.charAt(0) === '#') { 152 return document.getElementById(elem.substring(1)) 153 } else if (elem.charAt(0) === '.') { 154 return document.querySelectorAll(elem)[0] 155 } else { 156 return null 157 } 158 159} 160 161function closeByClickingOutside(props) { 162 163 console.log('click'); 164 165 166 /* 167 panel.addEventListener('blur', function(event) { 168 if (panel.contains(event.relatedTarget) || button.contains(event.relatedTarget)) { 169 // don't react to this 170 return; 171 } 172 document.body.classList.remove('a11y-sliding-menu--visible') 173 document.body.classList.add('a11y-sliding-menu--hidden') 174 button.setAttribute('aria-expanded', 'false') 175 panel.setAttribute('aria-hidden','true') 176 panel.setAttribute('tabIndex','-1') 177 page.setAttribute('tabIndex','0') 178 }); 179 */ 180} 181 182 183function closeByClickingButton(props) { 184 var button = returnElement(props.closeButton) 185 var headerButton = returnElement(props.toggler) 186 var panel = returnElement(props.panel) 187 188 if (button !== null && button !== undefined ) { 189 button.addEventListener('click', function() { 190 document.body.classList.remove('a11y-sliding-menu--visible') 191 document.body.classList.add('a11y-sliding-menu--hidden') 192 headerButton.setAttribute('aria-expanded', 'false') 193 panel.setAttribute('aria-hidden','true') 194 panel.setAttribute('aria-hidden','-1') 195 page.setAttribute('tabIndex', '0') 196 headerButton.focus() 197 },false) 198 } 199 200} 201 202function focusOnFirstElement(container) { 203 if (container !== undefined && container !== null) { 204 var focusable = container.querySelectorAll('a[href],input, button, [tabindex="-1"]') 205 focusable[0].focus() 206 } 207} 208 209// ---------------- 210// IE polyfills 211// ---------------- 212 213if (!Element.prototype.matches) { 214 Element.prototype.matches = Element.prototype.msMatchesSelector || 215 Element.prototype.webkitMatchesSelector; 216} 217 218if (!Element.prototype.closest) { 219 Element.prototype.closest = function(s) { 220 var el = this; 221 222 do { 223 if (Element.prototype.matches.call(el, s)) return el; 224 el = el.parentElement || el.parentNode; 225 } while (el !== null && el.nodeType === 1); 226 return null; 227 }; 228}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.