1/** 2 * Desktop nav: expandable search + live suggestions. 3 */ 4(function () { 5 var DEBOUNCE_MS = 120; 6 var MIN_CHARS = 2; 7 8 function qs(root, sel) { 9 return root.querySelector(sel); 10 } 11 12 function setOpen(root, open) { 13 var toggle = qs(root, ".nczd-nav-search__toggle"); 14 var panel = qs(root, ".nczd-nav-search__panel"); 15 var input = qs(root, ".nczd-nav-search__input"); 16 if (!toggle || !panel) return; 17 18 root.classList.toggle("is-open", open); 19 toggle.setAttribute("aria-expanded", open ? "true" : "false"); 20 if (open) { 21 panel.hidden = false; 22 window.setTimeout(function () { 23 if (input) { 24 input.focus(); 25 if ((input.value || "").trim().length >= MIN_CHARS) { 26 input.dispatchEvent(new Event("input", { bubbles: true })); 27 } 28 } 29 }, 30); 30 } else { 31 panel.hidden = true; 32 var results = qs(root, "[data-nczd-nav-search-results]"); 33 if (results) results.hidden = true; 34 } 35 } 36 37 function bind(root) { 38 if (!root || root._nczdSearchBound) return; 39 root._nczdSearchBound = true; 40 41 var toggle = qs(root, ".nczd-nav-search__toggle"); 42 var input = qs(root, ".nczd-nav-search__input"); 43 var results = qs(root, "[data-nczd-nav-search-results]"); 44 var list = qs(root, "[data-nczd-nav-search-list]"); 45 var preloader = qs(root, "[data-nczd-nav-search-preloader]"); 46 var timer = null; 47 var lastTerm = ""; 48 var xhr = null; 49 50 if (toggle) { 51 toggle.addEventListener("click", function (e) { 52 e.preventDefault(); 53 setOpen(root, !root.classList.contains("is-open")); 54 }); 55 } 56 57 document.addEventListener("keydown", function (e) { 58 if (e.key === "Escape" && root.classList.contains("is-open")) { 59 setOpen(root, false); 60 if (toggle) toggle.focus(); 61 } 62 }); 63 64 document.addEventListener("mousedown", function (e) { 65 if (!root.classList.contains("is-open")) return; 66 if (!root.contains(e.target)) setOpen(root, false); 67 }); 68 69 if (results) { 70 results.addEventListener( 71 "wheel", 72 function (e) { 73 if (results.hidden) return; 74 var max = results.scrollHeight - results.clientHeight; 75 if (max > 0) { 76 results.scrollTop = Math.min( 77 max, 78 Math.max(0, results.scrollTop + e.deltaY) 79 ); 80 } 81 e.preventDefault(); 82 e.stopPropagation(); 83 }, 84 { passive: false } 85 ); 86 } 87 88 function renderEmpty(msg) { 89 if (!list) return; 90 list.innerHTML = 91 '<div class="nczd-nav-search__empty">' + 92 (msg || "ÐиÑего не найдено") + 93 "</div>"; 94 } 95 96 function runSearch(term) { 97 if (!window.nczdNavSearch || !window.nczdNavSearch.ajaxUrl) return; 98 if (xhr && typeof xhr.abort === "function") xhr.abort(); 99 100 if (preloader) preloader.hidden = false; 101 if (results) results.hidden = false; 102 if (list) list.innerHTML = ""; 103 104 xhr = new XMLHttpRequest(); 105 xhr.open("POST", window.nczdNavSearch.ajaxUrl, true); 106 xhr.setRequestHeader( 107 "Content-Type", 108 "application/x-www-form-urlencoded; charset=UTF-8" 109 ); 110 xhr.onload = function () { 111 if (preloader) preloader.hidden = true; 112 if (xhr.status >= 200 && xhr.status < 300) { 113 var html = (xhr.responseText || "").trim(); 114 if (list) { 115 list.innerHTML = html || ""; 116 if (!html) renderEmpty(); 117 } 118 } else { 119 renderEmpty("ÐÑибка поиÑка"); 120 } 121 }; 122 xhr.onerror = function () { 123 if (preloader) preloader.hidden = true; 124 renderEmpty("ÐÑибка поиÑка"); 125 }; 126 xhr.send( 127 "action=" + 128 encodeURIComponent(window.nczdNavSearch.action) + 129 "&term=" + 130 encodeURIComponent(term) 131 ); 132 } 133 134 if (input) { 135 input.addEventListener("input", function () { 136 var term = (input.value || "").trim(); 137 window.clearTimeout(timer); 138 if (term.length < MIN_CHARS) { 139 lastTerm = term; 140 if (results) results.hidden = true; 141 if (list) list.innerHTML = ""; 142 return; 143 } 144 if (term === lastTerm) return; 145 timer = window.setTimeout(function () { 146 lastTerm = term; 147 runSearch(term); 148 }, DEBOUNCE_MS); 149 }); 150 } 151 } 152 153 function init() { 154 document 155 .querySelectorAll("[data-nczd-nav-search]") 156 .forEach(bind); 157 } 158 159 if (document.readyState === "loading") { 160 document.addEventListener("DOMContentLoaded", init); 161 } else { 162 init(); 163 } 164})();
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.