1/* The page holds still while anything is open over it. Counted, because the drawer and the sheet 2 can be open at once and the first to close must not unlock the page under the second. */ 3(function () { 4 'use strict'; 5 var open = 0; 6 window.cilHoldPage = function (hold) { 7 open = Math.max(0, open + (hold ? 1 : -1)); 8 // The gutter is reserved in the stylesheet, so holding the page still changes no widths. 9 document.documentElement.classList.toggle('cil-noscroll', open > 0); 10 }; 11})(); 12 13/* The language sheet: opening it, closing it, and giving it back the focus it borrowed. 14 15 The sheet is `hidden` at rest rather than merely transparent, so nothing inside it is reachable 16 by tab or read aloud while it is down. Opening therefore takes two steps â reveal, then let the 17 next frame animate the class â because a transform cannot ease from a box that was not laid out. */ 18(function () { 19 'use strict'; 20 21 var button = document.getElementById('cilMobileLanguages'); 22 var sheet = document.getElementById('cilMobileLanguageSheet'); 23 if (!button || !sheet) return; 24 25 var opener = null; // whatever had the focus before the sheet took it 26 27 function open() { 28 opener = document.activeElement; 29 sheet.hidden = false; 30 // Read a laid-out box before adding the class, so the panel eases up instead of appearing up. 31 void sheet.offsetHeight; 32 sheet.classList.add('is-open'); 33 button.setAttribute('aria-expanded', 'true'); 34 window.cilHoldPage(true); 35 36 var first = sheet.querySelector('.cil-sheet__row'); 37 if (first && first.focus) first.focus({preventScroll: true}); 38 } 39 40 function close() { 41 if (!sheet.classList.contains('is-open')) return; 42 sheet.classList.remove('is-open'); 43 button.setAttribute('aria-expanded', 'false'); 44 window.cilHoldPage(false); 45 46 // Stays in the layout until the panel has finished leaving, then goes out of reach again. 47 var done = function () { sheet.hidden = true; }; 48 var panel = sheet.querySelector('.cil-sheet__panel'); 49 if (panel && window.getComputedStyle(panel).transitionDuration !== '0s') { 50 panel.addEventListener('transitionend', done, {once: true}); 51 } else { 52 done(); 53 } 54 55 if (opener && opener.focus) opener.focus({preventScroll: true}); 56 opener = null; 57 } 58 59 button.addEventListener('click', function (e) { 60 e.preventDefault(); 61 if (sheet.classList.contains('is-open')) close(); else open(); 62 }); 63 64 /* The drawer asks for the same sheet, so there is one list of languages on this page and not 65 two that could disagree about which one you are reading. */ 66 var drawerLanguages = document.getElementById('cilDrawerLanguages'); 67 if (drawerLanguages) { 68 drawerLanguages.addEventListener('click', function (e) { 69 e.preventDefault(); 70 if (sheet.classList.contains('is-open')) close(); else open(); 71 }); 72 } 73 74 // The scrim and the handle both say "no thank you". 75 sheet.addEventListener('click', function (e) { 76 if (e.target.closest('[data-cil-sheet-close]')) close(); 77 }); 78 79 document.addEventListener('keydown', function (e) { 80 if (e.key === 'Escape') close(); 81 }); 82 83 /* The mark that asks for the field. The bar already wears the field once the page has moved; 84 before that, pressing the mark puts the bar into the same shape and hands over the caret. */ 85 var toggle = document.getElementById('cilMobileSearchToggle'); 86 var mobile = document.querySelector('.cil-mhdr'); 87 var form = document.getElementById('cilMobileSearchForm'); 88 89 if (toggle && mobile && form) { 90 toggle.addEventListener('click', function () { 91 mobile.classList.add('is-searching'); 92 toggle.setAttribute('aria-expanded', 'true'); 93 var input = form.querySelector('input'); 94 if (input) input.focus({preventScroll: true}); 95 }); 96 97 // Leaving an empty field gives the wordmark back, so the bar is not left looking searched. 98 form.addEventListener('focusout', function () { 99 window.setTimeout(function () { 100 if (form.contains(document.activeElement)) return; 101 var input = form.querySelector('input'); 102 if (input && input.value.trim() !== '') return; 103 mobile.classList.remove('is-searching'); 104 toggle.setAttribute('aria-expanded', 'false'); 105 }, 0); 106 }); 107 } 108})(); 109 110/* The drawer behind the burger. 111 112 Same shape as the sheet: `hidden` at rest so nothing inside is reachable while it is closed, then 113 revealed a frame before the class that animates it. Kept separate from the sheet's script above 114 because the two can be open at once â the drawer's foot asks for the sheet. */ 115(function () { 116 'use strict'; 117 118 var burger = document.getElementById('cilMobileMenuToggle'); 119 var drawer = document.getElementById('cilMobileDrawer'); 120 if (!burger || !drawer) return; 121 122 var panel = drawer.querySelector('.cil-drawer__panel'); 123 var opener = null; 124 125 function open() { 126 opener = document.activeElement; 127 drawer.hidden = false;
128 void drawer.offsetHeight; 129 drawer.classList.add('is-open'); 130 burger.setAttribute('aria-expanded', 'true'); 131 window.cilHoldPage(true); 132 133 var first = drawer.querySelector('.cil-drawer__close'); 134 if (first && first.focus) first.focus({preventScroll: true}); 135 } 136 137 function close() { 138 if (!drawer.classList.contains('is-open')) return; 139 drawer.classList.remove('is-open'); 140 burger.setAttribute('aria-expanded', 'false'); 141 window.cilHoldPage(false); 142 143 var done = function () { drawer.hidden = true; }; 144 if (panel && window.getComputedStyle(panel).transitionDuration !== '0s') { 145 panel.addEventListener('transitionend', done, {once: true}); 146 } else { 147 done(); 148 } 149 150 if (opener && opener.focus) opener.focus({preventScroll: true}); 151 opener = null; 152 153 // Whatever was showing inside can put itself away. The drawer does not know what the 154 // catalogue is; it only says that it has closed. 155 drawer.dispatchEvent(new CustomEvent('cil:drawer-closed')); 156 } 157 158 burger.setAttribute('aria-controls', 'cilMobileDrawer'); 159 burger.setAttribute('aria-expanded', 'false'); 160 burger.addEventListener('click', function (e) { 161 e.preventDefault(); 162 if (drawer.classList.contains('is-open')) close(); else open(); 163 }); 164 165 drawer.addEventListener('click', function (e) { 166 if (e.target.closest('[data-cil-drawer-close]')) close(); 167 }); 168 169 document.addEventListener('keydown', function (e) { 170 // The sheet may be over the drawer; it answers Escape first and leaves the drawer standing. 171 var sheet = document.getElementById('cilMobileLanguageSheet'); 172 if (e.key !== 'Escape') return; 173 if (sheet && sheet.classList.contains('is-open')) return; 174 close(); 175 }); 176})(); 177 178/* The catalogue inside the drawer: two levels, one on screen at a time. 179 180 Everything is already in the markup, so this only decides which level shows. Opening it hides the 181 drawer's own list rather than replacing it, so closing the catalogue puts the drawer back exactly 182 as it was rather than rebuilding it. */ 183(function () { 184 'use strict'; 185 186 var drawer = document.getElementById('cilMobileDrawer'); 187 var cat = document.getElementById('cilMobileCatalogue'); 188 if (!drawer || !cat) return; 189 190 var levels = cat.querySelectorAll('[data-cil-cat-level]'); 191 192 function show(name) { 193 for (var i = 0; i < levels.length; i++) { 194 var isIt = levels[i].getAttribute('data-cil-cat-level') === name; 195 levels[i].hidden = !isIt; 196 levels[i].classList.toggle('is-current', isIt); 197 } 198 // Only when the drawer is actually on screen; resetting a closed one must not take focus. 199 if (drawer.classList.contains('is-open')) { 200 var head = cat.querySelector('[data-cil-cat-level="' + name + '"] .cil-cat__head'); 201 if (head && head.focus) head.focus({preventScroll: true}); 202 } 203 } 204 205 function open() { 206 cat.hidden = false; 207 drawer.classList.add('is-catalogue'); 208 show('root'); 209 } 210 211 /* `moveFocus` is false when the whole drawer is going away: the drawer has already handed the 212 focus back to the burger, and taking it into a panel that is now hidden would lose it. */ 213 function close(moveFocus) { 214 cat.hidden = true; 215 drawer.classList.remove('is-catalogue'); 216 if (moveFocus === false) return; 217 var back = drawer.querySelector('[data-cil-drawer-catalogue]'); 218 if (back && back.focus) back.focus({preventScroll: true}); 219 } 220 221 /* Closing the drawer with the catalogue open used to leave it open behind the scenes, so the 222 next tap of the burger gave the catalogue again and the menu appeared to have gone. The 223 drawer always reopens on its own list. */ 224 drawer.addEventListener('cil:drawer-closed', function () { 225 if (cat.hidden) return; 226 close(false); 227 show('root'); 228 }); 229 230 // The drawer's catalogue row is the way in. 231 drawer.addEventListener('click', function (e) { 232 var opener = e.target.closest('[data-cil-drawer-catalogue]'); 233 if (opener) { e.preventDefault(); open(); return; } 234 235 var into = e.target.closest('[data-cil-cat-open]'); 236 if (into) { e.preventDefault(); show(into.getAttribute('data-cil-cat-open')); return; } 237 238 var back = e.target.closest('[data-cil-cat-back]'); 239 if (back) { 240 e.preventDefault(); 241 var to = back.getAttribute('data-cil-cat-back'); 242 if (to === 'drawer') close(); else show(to); 243 } 244 }); 245})();
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.