1(function (Drupal, drupalSettings) { 2 Drupal.behaviors.email_autocomplete = { 3 attach: function (context, settings) { 4 const domainSuggestions = drupalSettings?.sb_forms?.domains || []; 5 6 context.querySelectorAll('input[type="email"]').forEach((emailInput) => { 7 //emailInput.classList.add('email-autocomplete-processed'); 8 9 const wrapper = emailInput.closest('.email__suggestions'); 10 if (!wrapper) { 11 return; 12 } 13 14 let suggestionsBox = wrapper.querySelector('.js-suggestions'); 15 if (!suggestionsBox) { 16 suggestionsBox = document.createElement('div'); 17 suggestionsBox.className = 'js-suggestions'; 18 suggestionsBox.style.position = 'absolute'; 19 suggestionsBox.style.border = '1px solid #ccc'; 20 suggestionsBox.style.background = 'white'; 21 suggestionsBox.style.display = 'none'; 22 suggestionsBox.style.zIndex = '1000'; 23 suggestionsBox.style.width = '100%'; 24 wrapper.appendChild(suggestionsBox); 25 } 26 27 let currentSelection = -1; 28 29 function showSuggestions(filtered) { 30 suggestionsBox.innerHTML = ''; 31 filtered.forEach((domain, index) => { 32 const div = document.createElement('div'); 33 div.className = 'js-suggestions-item'; 34 div.textContent = emailInput.value.slice(0, emailInput.value.indexOf('@') + 1) + domain; 35 div.style.padding = '8px'; 36 div.style.cursor = 'pointer'; 37 div.addEventListener('mousedown', (e) => { 38 e.preventDefault(); 39 applySuggestion(domain); 40 }); 41 suggestionsBox.appendChild(div); 42 }); 43 44 suggestionsBox.style.display = filtered.length ? 'block' : 'none'; 45 currentSelection = -1; 46 } 47 48 function applySuggestion(domain) { 49 const atIndex = emailInput.value.indexOf('@'); 50 if (atIndex !== -1) { 51 emailInput.value = emailInput.value.slice(0, atIndex + 1) + domain; 52 } 53 hideSuggestions(); 54 } 55 56 function hideSuggestions() { 57 suggestionsBox.style.display = 'none'; 58 currentSelection = -1; 59 } 60 61 emailInput.addEventListener('input', () => { 62 const value = emailInput.value; 63 const atIndex = value.indexOf('@'); 64 if (atIndex !== -1) { 65 const query = value.slice(atIndex + 1).toLowerCase(); 66 const filtered = domainSuggestions.filter(domain => domain.startsWith(query)); 67 showSuggestions(filtered); 68 } else { 69 hideSuggestions(); 70 } 71 }); 72 73 emailInput.addEventListener('keydown', (e) => { 74 const items = suggestionsBox.querySelectorAll('.js-suggestions-item'); 75 if (suggestionsBox.style.display === 'block' && items.length > 0) { 76 if (e.key === 'ArrowDown') { 77 e.preventDefault(); 78 currentSelection = (currentSelection + 1) % items.length; 79 } else if (e.key === 'ArrowUp') { 80 e.preventDefault(); 81 currentSelection = (currentSelection - 1 + items.length) % items.length; 82 } else if (e.key === 'Enter' && currentSelection >= 0) { 83 e.preventDefault(); 84 applySuggestion(items[currentSelection].textContent.split('@')[1]); 85 } 86 87 items.forEach((item, index) => { 88 item.style.backgroundColor = index === currentSelection ? '#f0f0f0' : 'white'; 89 }); 90 } 91 }); 92 93 document.addEventListener('click', (e) => { 94 if (!wrapper.contains(e.target)) { 95 hideSuggestions(); 96 } 97 }); 98 }); 99 } 100 }; 101})(Drupal, drupalSettings);
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.