Add searchable manufacturer picker

This commit is contained in:
2026-08-05 15:50:36 +02:00
parent 1914c7d141
commit a1e3f537e3
6 changed files with 181 additions and 2 deletions
+72
View File
@@ -2,6 +2,11 @@
const fieldGrid = document.querySelector("#fieldGrid");
const variantHeader = document.querySelector("#variantHeader");
const manufacturerSelect = document.querySelector("#manufacturerSelect");
const manufacturerTrigger = document.querySelector("#manufacturerTrigger");
const manufacturerMenu = document.querySelector("#manufacturerMenu");
const manufacturerSearch = document.querySelector("#manufacturerSearch");
const manufacturerOptions = document.querySelector("#manufacturerOptions");
const manufacturerValue = document.querySelector("#manufacturerValue");
const languageSelect = document.querySelector("#languageSelect");
const recordIdElement = document.querySelector("#recordId");
const loadProductButton = document.querySelector("#loadProductButton");
@@ -136,6 +141,8 @@ await loadManufacturers();
await loadLanguages();
manufacturerSelect.addEventListener("change", () => {
syncManufacturerPickerLabel();
closeManufacturerPicker();
if (manufacturerSelect.value) {
loadMappingSources();
loadProductForSelectedManufacturer(1);
@@ -145,6 +152,15 @@ manufacturerSelect.addEventListener("change", () => {
}
});
manufacturerTrigger.addEventListener("click", toggleManufacturerPicker);
manufacturerSearch.addEventListener("input", renderManufacturerOptions);
manufacturerSearch.addEventListener("keydown", (event) => {
if (event.key === "Escape") closeManufacturerPicker();
});
document.addEventListener("click", (event) => {
if (!event.target.closest("#manufacturerPicker")) closeManufacturerPicker();
});
loadProductButton.disabled = true;
loadProductButton.title = "Load existing product attribute info.";
loadProductButton.addEventListener("click", loadProductInfoForCurrentProduct);
@@ -272,8 +288,64 @@ async function loadManufacturers() {
manufacturerSelect.append(createOption(String(manufacturer.id), manufacturer.name));
}
if (data.message) manufacturerSelect.append(createOption("", data.message));
syncManufacturerPickerLabel();
renderManufacturerOptions();
} catch (error) {
manufacturerSelect.append(createOption("", error.message || "Local DB is not configured."));
syncManufacturerPickerLabel();
renderManufacturerOptions();
}
}
function toggleManufacturerPicker() {
if (manufacturerMenu.hidden) {
manufacturerMenu.hidden = false;
manufacturerTrigger.setAttribute("aria-expanded", "true");
manufacturerSearch.value = "";
renderManufacturerOptions();
if (manufacturerSelect.options.length > 11) manufacturerSearch.focus();
} else {
closeManufacturerPicker();
}
}
function closeManufacturerPicker() {
manufacturerMenu.hidden = true;
manufacturerTrigger.setAttribute("aria-expanded", "false");
}
function syncManufacturerPickerLabel() {
const option = manufacturerSelect.selectedOptions[0];
manufacturerValue.textContent = option?.textContent || "Select manufacturer";
}
function renderManufacturerOptions() {
const options = [...manufacturerSelect.options].filter((option) => option.value);
const query = manufacturerSearch.value.trim().toLocaleLowerCase();
const filtered = options.filter((option) => option.textContent.toLocaleLowerCase().includes(query));
const visible = filtered.slice(0, 10);
manufacturerOptions.replaceChildren(
...visible.map((option) => {
const item = document.createElement("button");
item.className = "manufacturer-option";
item.type = "button";
item.setAttribute("role", "option");
item.textContent = option.textContent;
item.setAttribute("aria-selected", String(option.value === manufacturerSelect.value));
item.addEventListener("click", () => {
manufacturerSelect.value = option.value;
manufacturerSelect.dispatchEvent(new Event("change", { bubbles: true }));
});
return item;
}),
);
if (!visible.length) {
const empty = document.createElement("div");
empty.className = "manufacturer-empty";
empty.textContent = "No manufacturer found.";
manufacturerOptions.append(empty);
}
}