fix: separate tree arrow (expand) from label (filter) in catalog
Arrow ▶ only toggles expand/collapse. Node label click filters products. Forms inside tree (Add Category, Add District, etc.) no longer trigger navigation when clicking their buttons or inputs.
This commit is contained in:
@@ -291,7 +291,6 @@ pre { font-size: 0.8rem; white-space: pre-wrap; word-break: break-all; max-width
|
||||
.tree-node { margin-left: 0; }
|
||||
|
||||
.tree-toggle {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
padding: 0.4rem 0;
|
||||
display: flex;
|
||||
@@ -308,10 +307,16 @@ pre { font-size: 0.8rem; white-space: pre-wrap; word-break: break-all; max-width
|
||||
transition: transform 0.15s;
|
||||
width: 12px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tree-toggle .arrow.open { transform: rotate(90deg); }
|
||||
|
||||
.tree-toggle .node-label {
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.tree-children { display: none; }
|
||||
|
||||
.tree-children.open { display: block; }
|
||||
|
||||
@@ -12,7 +12,7 @@ export function renderCatalog(tree, products, filter, categories, subcategories,
|
||||
const editFormHtml = renderProductEditForm('/catalog/products/__ID__/edit', catOptions, subcatJson, locations)
|
||||
.replace(/`/g, '\\`').replace(/\$/g, '\\$');
|
||||
|
||||
let treeHtml = '<div class="tree-node"><div class="tree-toggle" data-all="1"><span class="arrow">▶</span> <strong>All Products</strong><span class="tree-count">(' + products.length + ')</span></div></div>';
|
||||
let treeHtml = '<div class="tree-node"><div class="tree-toggle"><span class="arrow" data-toggle="1">▶</span> <span class="node-label" data-all="1"><strong>All Products</strong></span><span class="tree-count">(' + products.length + ')</span></div></div>';
|
||||
for (const [country, cdata] of Object.entries(tree)) {
|
||||
let countryCount = 0, cityHtml = '';
|
||||
for (const [city, ddata] of Object.entries(cdata.cities)) {
|
||||
@@ -24,17 +24,17 @@ export function renderCatalog(tree, products, filter, categories, subcategories,
|
||||
districtCount += catCount;
|
||||
let subHtml = '';
|
||||
for (const s of (c.subs||[])) {
|
||||
subHtml += `<div class="tree-node"><div class="tree-toggle" data-sub="${s.id}"><span class="arrow">▶</span> ${esc(s.name)}<span class="tree-count">(${s.pc||0})</span><span class="tree-actions"><form method="POST" action="/catalog/subcategories/${s.id}/delete" onsubmit="return confirm('Delete?')"><button class="btn-sm btn-danger">✕</button></form></span></div><div class="tree-children"><form method="POST" action="/catalog/categories/${c.id}/subcategories" class="inline-form tree-add"><input name="name" placeholder="+ Subcategory" required size="12"><button class="btn-sm">Add</button></form></div></div>`;
|
||||
subHtml += `<div class="tree-node"><div class="tree-toggle"><span class="arrow" data-toggle="1">▶</span> <span class="node-label" data-sub="${s.id}">${esc(s.name)}</span><span class="tree-count">(${s.pc||0})</span><span class="tree-actions"><form method="POST" action="/catalog/subcategories/${s.id}/delete" onsubmit="return confirm('Delete?')"><button class="btn-sm btn-danger">✕</button></form></span></div><div class="tree-children"><form method="POST" action="/catalog/categories/${c.id}/subcategories" class="inline-form tree-add"><input name="name" placeholder="+ Subcategory" required size="12"><button class="btn-sm">Add</button></form></div></div>`;
|
||||
}
|
||||
catHtml += `<div class="tree-node"><div class="tree-toggle" data-cat="${c.id}"><span class="arrow">▶</span> ${esc(c.name)}<span class="tree-count">(${catCount})</span><span class="tree-actions"><form method="POST" action="/catalog/categories/${c.id}/delete" onsubmit="return confirm('Delete?')"><button class="btn-sm btn-danger">✕</button></form></span></div><div class="tree-children">${subHtml}<form method="POST" action="/catalog/categories/${c.id}/subcategories" class="inline-form tree-add"><input name="name" placeholder="+ Subcategory" required size="12"><button class="btn-sm">Add</button></form></div></div>`;
|
||||
catHtml += `<div class="tree-node"><div class="tree-toggle"><span class="arrow" data-toggle="1">▶</span> <span class="node-label" data-cat="${c.id}">${esc(c.name)}</span><span class="tree-count">(${catCount})</span><span class="tree-actions"><form method="POST" action="/catalog/categories/${c.id}/delete" onsubmit="return confirm('Delete?')"><button class="btn-sm btn-danger">✕</button></form></span></div><div class="tree-children">${subHtml}<form method="POST" action="/catalog/categories/${c.id}/subcategories" class="inline-form tree-add"><input name="name" placeholder="+ Subcategory" required size="12"><button class="btn-sm">Add</button></form></div></div>`;
|
||||
}
|
||||
districtHtml += `<div class="tree-node"><div class="tree-toggle" data-loc="${ldata.id}"><span class="arrow">▶</span> ${esc(district)}<span class="tree-count">(${districtCount})</span><span class="tree-actions"><form method="POST" action="/catalog/locations/${ldata.id}/delete" onsubmit="return confirm('Delete?')"><button class="btn-sm btn-danger">✕</button></form></span></div><div class="tree-children">${catHtml}<form method="POST" action="/catalog/categories" class="inline-form tree-add"><input type="hidden" name="location_id" value="${ldata.id}"><input name="name" placeholder="+ Category" required size="12"><button class="btn-sm">Add</button></form></div></div>`;
|
||||
districtHtml += `<div class="tree-node"><div class="tree-toggle"><span class="arrow" data-toggle="1">▶</span> <span class="node-label" data-loc="${ldata.id}">${esc(district)}</span><span class="tree-count">(${districtCount})</span><span class="tree-actions"><form method="POST" action="/catalog/locations/${ldata.id}/delete" onsubmit="return confirm('Delete?')"><button class="btn-sm btn-danger">✕</button></form></span></div><div class="tree-children">${catHtml}<form method="POST" action="/catalog/categories" class="inline-form tree-add"><input type="hidden" name="location_id" value="${ldata.id}"><input name="name" placeholder="+ Category" required size="12"><button class="btn-sm">Add</button></form></div></div>`;
|
||||
cityCount += districtCount;
|
||||
}
|
||||
cityHtml += `<div class="tree-node"><div class="tree-toggle" data-city="${city}" data-country="${esc(country)}"><span class="arrow">▶</span> ${esc(city)}<span class="tree-count">(${cityCount})</span><span class="tree-actions"><form method="POST" action="/catalog/locations/add-district" class="inline-form tree-add"><input type="hidden" name="country" value="${esc(country)}"><input type="hidden" name="city" value="${esc(city)}"><input name="district" placeholder="+ District" required size="12"><button class="btn-sm">Add</button></form></span></div><div class="tree-children">${districtHtml}</div></div>`;
|
||||
cityHtml += `<div class="tree-node"><div class="tree-toggle"><span class="arrow" data-toggle="1">▶</span> <span class="node-label" data-city="${city}" data-country="${esc(country)}">${esc(city)}</span><span class="tree-count">(${cityCount})</span><span class="tree-actions"><form method="POST" action="/catalog/locations/add-district" class="inline-form tree-add"><input type="hidden" name="country" value="${esc(country)}"><input type="hidden" name="city" value="${esc(city)}"><input name="district" placeholder="+ District" required size="12"><button class="btn-sm">Add</button></form></span></div><div class="tree-children">${districtHtml}</div></div>`;
|
||||
countryCount += cityCount;
|
||||
}
|
||||
treeHtml += `<div class="tree-node"><div class="tree-toggle" data-country="${esc(country)}"><span class="arrow">▶</span> <strong>${esc(country)}</strong><span class="tree-count">(${countryCount})</span><span class="tree-actions"><form method="POST" action="/catalog/locations/add-city" class="inline-form tree-add"><input type="hidden" name="country" value="${esc(country)}"><input name="city" placeholder="+ City" required size="10"><button class="btn-sm">Add</button></form></span></div><div class="tree-children">${cityHtml}</div></div>`;
|
||||
treeHtml += `<div class="tree-node"><div class="tree-toggle"><span class="arrow" data-toggle="1">▶</span> <span class="node-label" data-country="${esc(country)}"><strong>${esc(country)}</strong></span><span class="tree-count">(${countryCount})</span><span class="tree-actions"><form method="POST" action="/catalog/locations/add-city" class="inline-form tree-add"><input type="hidden" name="country" value="${esc(country)}"><input name="city" placeholder="+ City" required size="10"><button class="btn-sm">Add</button></form></span></div><div class="tree-children">${cityHtml}</div></div>`;
|
||||
}
|
||||
|
||||
let tableHtml = '<p class="muted">No products found.</p>';
|
||||
@@ -181,12 +181,17 @@ async function addCategoryInline() {
|
||||
|
||||
function escHtml(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
|
||||
|
||||
document.querySelectorAll('.tree-toggle').forEach(el=>{el.addEventListener('click',()=>{
|
||||
const ch=el.nextElementSibling; if(!ch||!ch.classList.contains('tree-children')) return;
|
||||
ch.classList.toggle('open'); el.querySelector('.arrow').classList.toggle('open');
|
||||
document.querySelectorAll('.tree-toggle .arrow').forEach(el=>{el.addEventListener('click',e=>{
|
||||
e.stopPropagation();
|
||||
const toggle=el.closest('.tree-toggle');
|
||||
const ch=toggle.nextElementSibling; if(!ch||!ch.classList.contains('tree-children')) return;
|
||||
ch.classList.toggle('open'); el.classList.toggle('open');
|
||||
})});
|
||||
document.querySelectorAll('.tree-toggle .node-label').forEach(el=>{el.addEventListener('click',e=>{
|
||||
e.stopPropagation();
|
||||
const loc=el.dataset.loc, cat=el.dataset.cat, sub=el.dataset.sub, all=el.dataset.all;
|
||||
if(loc||cat||sub||all){ let u='/catalog?'; if(loc) u+='loc='+loc; if(cat) u+='cat='+cat; if(sub) u+='sub='+sub; location.href=u; }
|
||||
})});
|
||||
});
|
||||
function openAdd(){ document.getElementById('modal-body').innerHTML=addFormTpl; initLocationSelects(null); document.getElementById('product-modal').style.display='flex'; }
|
||||
async function openEdit(id){ const r=await fetch('/catalog/products/'+id+'/json'); const p=await r.json();
|
||||
document.getElementById('modal-body').innerHTML=editFormTpl.replace('/__ID__/','/'+p.id+'/'); fillEditForm(p); document.getElementById('product-modal').style.display='flex'; }
|
||||
|
||||
Reference in New Issue
Block a user