const state = { rows: [], mode: "machine", suggestionIndex: -1 }; const labels = { oil_fuel_filters: "Olej / paliwo", air_cooling_filters: "Powietrze / chłodzenie", hydraulic_other_filters: "Hydrauliczny / inne" }; const $ = (selector) => document.querySelector(selector); function parseCsv(text) { const rows = [], record = []; let field = "", quoted = false; for (let i = 0; i < text.length; i += 1) { const char = text[i], next = text[i + 1]; if (char === '"' && quoted && next === '"') { field += '"'; i += 1; } else if (char === '"') quoted = !quoted; else if (char === "," && !quoted) { record.push(field); field = ""; } else if ((char === "\n" || char === "\r") && !quoted) { if (char === "\r" && next === "\n") i += 1; record.push(field); field = ""; if (record.some((value) => value.trim())) rows.push(record.splice(0)); } else field += char; } record.push(field); if (record.some((value) => value.trim())) rows.push(record); const headers = rows.shift().map((header) => header.replace(/^\uFEFF/, "").trim()); return rows.map((values) => Object.fromEntries(headers.map((header, index) => [header, (values[index] || "").trim()]))); } function normalized(value) { return (value || "").toLocaleLowerCase("pl-PL").normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } function escapeHtml(value) { return String(value || "").replace(/[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[char])); } function highlighted(value, query) { const safe = escapeHtml(value); if (!query) return safe; const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); return safe.replace(new RegExp(`(${escaped})`, "ig"), "$1"); } function allFilterText(row) { return ["oil_fuel_filters", "air_cooling_filters", "hydraulic_other_filters"].map((key) => row[key]).join(" "); } function filterParts(value) { const parts = value.split(/\s*\|\s*|(?=(?:Olej|Paliwo|Powietrze|Hydrauliczny|Odpowietrznik|Płyn|Kabinowy)\b)/i) .map((part) => part.replace(/\s*\|\s*$/, "").trim()).filter(Boolean); return parts.length ? parts : [value]; } function suggestionData(query) { const needle = normalized(query); if (state.mode === "machine") { return [...new Set(state.rows.map((row) => row.model).filter(Boolean))] .filter((value) => normalized(value).includes(needle)) .sort((a, b) => a.localeCompare(b, "pl")) .slice(0, 8) .map((value) => ({ value, meta: "model maszyny" })); } const values = new Map(); Object.entries(labels).forEach(([key, label]) => { state.rows.forEach((row) => { const value = row[key]; if (!value) return; filterParts(value).forEach((part) => { if (normalized(part).includes(needle) && !values.has(part)) values.set(part, label); }); }); }); return [...values.entries()].sort(([a], [b]) => a.localeCompare(b, "pl")).slice(0, 8) .map(([value, meta]) => ({ value, meta })); } function renderSuggestions() { const input = $("#searchInput"); const query = input.value.trim(); const container = $("#suggestions"); state.suggestionIndex = -1; if (query.length < 2 || !state.rows.length) { container.classList.remove("visible"); container.innerHTML = ""; return; } const suggestions = suggestionData(query); container.innerHTML = suggestions.map((item, index) => ``).join(""); container.classList.toggle("visible", suggestions.length > 0); container.querySelectorAll(".suggestion").forEach((button) => button.addEventListener("mousedown", (event) => { event.preventDefault(); input.value = button.dataset.value; container.classList.remove("visible"); $("#clearButton").classList.add("visible"); render(); })); } function render() { const query = $("#searchInput").value.trim(); const needle = normalized(query); const results = state.rows.filter((row) => { const haystack = state.mode === "machine" ? [row.model, row.machine_type, row.engine, row.year, row.notes].join(" ") : allFilterText(row); return !needle || normalized(haystack).includes(needle); }); $("#resultsTitle").textContent = state.mode === "machine" ? (query ? "Pasujące maszyny" : "Maszyny w bazie") : (query ? "Maszyny pasujące do filtra" : "Wyszukaj numer filtra"); $("#resultCount").textContent = query ? `${results.length} wyników` : `${state.rows.length} rekordów`; const container = $("#results"); container.innerHTML = ""; if (!results.length) { container.innerHTML = `