1/** 2 * Show, focus and dismiss the header search input. 3 */ 4((Drupal) => { 5 Drupal.behaviors.headerSearch = { 6 attach(context) { 7 8 // Only run if the relevant search input is found. 9 if (context.querySelector('#header-search')) { 10 11 // Get the necessary elements. 12 const searchDisplay = context.querySelector('#header-search-show'); 13 const searchDismiss = context.querySelector('#header-search-dismiss'); 14 const searchDismissIcon = context.querySelector('#search-dismiss-icon'); 15 const searchElement = context.querySelector('#header-search'); 16 const searchInput = context.querySelector('#header-search-input'); 17 const searchTrigger = context.querySelector('#header-search-trigger'); 18 const headerActions = context.querySelector('#header-actions'); 19 20 // Disable tabbing until visible, to prevent layout shift. 21 searchInput.tabIndex = '-1'; 22 searchDismiss.tabIndex = '-1'; 23 searchTrigger.tabIndex = '-1'; 24 25 // Run the rotate transform while invisible to avoid sluggishness on first trigger. 26 searchDismissIcon.style.transform = 'rotate(360deg)'; 27 28 // Show and focus the header search input. 29 function handleSearchDisplay() { 30 headerActions.classList.add('opacity-0'); 31 searchElement.classList.remove('translate-x-full'); 32 searchElement.classList.remove('opacity-0'); 33 searchDismissIcon.style.transform = 'rotate(-360deg)'; 34 35 // Allow relevant elements to receive focus. 36 searchInput.removeAttribute('tabindex'); 37 searchDismiss.removeAttribute('tabindex'); 38 searchTrigger.removeAttribute('tabindex'); 39 40 // Set the focus to the search input. 41 searchInput.focus({ preventScroll: true }); 42 } 43 44 // Handle the actual search. 45 function handleSearch() { 46 if (searchInput.value !== '') { 47 window.location = '/global-search?search=' + searchInput.value; 48 } 49 } 50 51 // Dismiss the search element. 52 function handleSearchDismiss() { 53 searchDismissIcon.style.transform = 'rotate(360deg)'; 54 setTimeout(() => { 55 headerActions.classList.remove('opacity-0'); 56 searchElement.classList.add('translate-x-full'); 57 searchElement.classList.add('opacity-0'); 58 searchInput.value = ''; 59 60 // Prevent focus when dismissed. 61 searchInput.tabIndex = '-1'; 62 searchDismiss.tabIndex = '-1'; 63 searchTrigger.tabIndex = '-1'; 64 }, 200); 65 } 66 67 // Attach the event handlers to both click and keyboard events. 68 searchTrigger.addEventListener('click', handleSearch); 69 searchDisplay.addEventListener('click', handleSearchDisplay); 70 searchDismiss.addEventListener('click', handleSearchDismiss); 71 searchInput.addEventListener('keydown', (event) => { if (event.key === 'Enter') handleSearch() }); 72 searchDisplay.addEventListener('keydown', (event) => { if (event.key === 'Enter') handleSearchDisplay() }); 73 searchDismiss.addEventListener('keydown', (event) => { if (event.key === 'Enter') handleSearchDismiss() }); 74 } 75 } 76 }; 77})(Drupal);
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.