Add searchable manufacturer picker
This commit is contained in:
@@ -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");
|
||||
@@ -129,6 +134,8 @@ setTableWidth();
|
||||
await loadManufacturers();
|
||||
await loadLanguages();
|
||||
manufacturerSelect.addEventListener("change", () => {
|
||||
syncManufacturerPickerLabel();
|
||||
closeManufacturerPicker();
|
||||
if (manufacturerSelect.value) {
|
||||
loadMappingSources();
|
||||
loadProductForSelectedManufacturer(1);
|
||||
@@ -138,6 +145,16 @@ manufacturerSelect.addEventListener("change", () => {
|
||||
clearProductState("Select manufacturer to load data.");
|
||||
}
|
||||
});
|
||||
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);
|
||||
@@ -258,9 +275,59 @@ async function loadManufacturers() {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
function createOption(value, label) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -60,7 +60,17 @@
|
||||
<option value="">Select language</option>
|
||||
</select>
|
||||
|
||||
<select class="input-like" id="manufacturerSelect" aria-label="Manufacturer">
|
||||
<div class="manufacturer-picker" id="manufacturerPicker">
|
||||
<button class="manufacturer-trigger" id="manufacturerTrigger" type="button" aria-haspopup="listbox" aria-expanded="false">
|
||||
<span id="manufacturerValue">Select manufacturer</span>
|
||||
<span class="picker-chevron" aria-hidden="true">⌄</span>
|
||||
</button>
|
||||
<div class="manufacturer-menu" id="manufacturerMenu" hidden>
|
||||
<input class="manufacturer-search" id="manufacturerSearch" type="search" placeholder="Search manufacturer..." aria-label="Search manufacturer" />
|
||||
<div class="manufacturer-options" id="manufacturerOptions" role="listbox"></div>
|
||||
</div>
|
||||
</div>
|
||||
<select class="input-like native-manufacturer-select" id="manufacturerSelect" aria-label="Manufacturer">
|
||||
<option value="">Select manufacturer</option>
|
||||
</select>
|
||||
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user