PageSourceSearch

https://nczd.ru/wp-content/themes/flatsome-child/assets/js/header-nav-search.js

js nczd.ru collected 2026-10-02 05:00:02 UTC 4,217 bytes, 164 lines download raw bytes

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.